Commit 008bc53c authored by Matthew Edwards's avatar Matthew Edwards Committed by GitHub

Add partitioning and sorting operations to libcpp.algorithm (GH-3202)

* Add is_partitioned and partition to libcpp.algorithm
* Add is_sorted and is_sorted_until to libcpp.algorithm
* Add partition_copy, stable_partition, and partition_point to libcpp.algorithm
* Move tests for sort and partial_sort into cpp_stl_algo_sorting_ops, add greater to libcpp.functional
* Add partial_sort_copy to libcpp.algorithm
* Add stable_sort to libcpp.algorithm
* Add nth_element to libcpp.algorithm
* Add missing except specifiers in libcpp.algorithm
parent 1582d97d
This diff is collapsed.
from libcpp cimport bool
cdef extern from "<functional>" namespace "std" nogil: cdef extern from "<functional>" namespace "std" nogil:
cdef cppclass function[T]: cdef cppclass function[T]:
function() except + function() except +
...@@ -10,4 +12,10 @@ cdef extern from "<functional>" namespace "std" nogil: ...@@ -10,4 +12,10 @@ cdef extern from "<functional>" namespace "std" nogil:
function operator=(void*) function operator=(void*)
function operator=[U](U) function operator=[U](U)
bint operator bool() bool operator bool()
# Comparisons
cdef cppclass greater[T=*]:
# https://github.com/cython/cython/issues/3193
greater() except +
bool operator()(const T& lhs, const T& rhs) except +
# mode: run
# tag: cpp, werror, cpp11
from __future__ import print_function
from libcpp cimport bool
from libcpp.algorithm cimport is_partitioned, partition, partition_copy, stable_partition, partition_point
from libcpp.algorithm cimport for_each, copy, reverse
from libcpp.iterator cimport back_inserter
from libcpp.vector cimport vector
cdef bool is_even(int i):
return i % 2 == 0
def test_is_partitioned():
"""
>>> test_is_partitioned()
False
True
False
"""
cdef vector[int] values = range(10)
print(is_partitioned(values.begin(), values.end(), is_even))
partition(values.begin(), values.end(), &is_even)
print(is_partitioned(values.begin(), values.end(), is_even))
reverse(values.begin(), values.end())
print(is_partitioned(values.begin(), values.end(), is_even))
cdef int print_int(int v) except -1:
print(v, end=" ")
def print_partition(vector[int] values):
"""
Test partition.
>> print_partition(range(10))
0 8 2 6 4 * 5 3 7 1 9
"""
it = partition(values.begin(), values.end(), &is_even)
for_each(values.begin(), it, &print_int)
print("*", end=" ")
for_each(it, values.end(), &print_int)
print()
def partition_ints_even(vector[int] values):
"""
Test partition_copy.
>>> partition_ints_even(range(10))
([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
"""
cdef vector[int] even_values, odd_values
partition_copy(values.begin(), values.end(), back_inserter(even_values), back_inserter(odd_values), &is_even)
return even_values, odd_values
cdef bool is_positive(int v):
return v > 0
def partition_ints_positive(vector[int] values):
"""
Test stable_partition.
>>> partition_ints_positive([0, 0, 3, 0, 2, 4, 5, 0, 7])
[3, 2, 4, 5, 7, 0, 0, 0, 0]
"""
stable_partition(values.begin(), values.end(), &is_positive)
return values
def partition_point_ints_even(vector[int] values):
"""
Test partition_point.
>>> partition_point_ints_even([0, 8, 2, 6, 4, 5, 3, 7, 1, 9])
([0, 8, 2, 6, 4], [5, 3, 7, 1, 9])
"""
it = partition_point(values.begin(), values.end(), is_even)
cdef vector[int] even_values, odd_values
copy(values.begin(), it, back_inserter(even_values))
copy(it, values.end(), back_inserter(odd_values))
return even_values, odd_values
# mode: run
# tag: cpp, werror, cpp11
from __future__ import print_function
from libcpp cimport bool
from libcpp.algorithm cimport is_sorted, is_sorted_until, sort, partial_sort, partial_sort_copy, stable_sort
from libcpp.algorithm cimport nth_element
from libcpp.functional cimport greater
from libcpp.iterator cimport distance
from libcpp.string cimport string
from libcpp.vector cimport vector
def is_sorted_ints(vector[int] values):
"""
Test is_sorted.
>>> is_sorted_ints([3, 1, 4, 1, 5])
False
>>> is_sorted_ints([1, 1, 3, 4, 5])
True
"""
return is_sorted(values.begin(), values.end())
def initial_sorted_elements(vector[int] values):
"""
Test is_sorted_until.
>>> initial_sorted_elements([4, 1, 9, 5, 1, 3])
1
>>> initial_sorted_elements([4, 5, 9, 3, 1, 1])
3
>>> initial_sorted_elements([9, 3, 1, 4, 5, 1])
1
>>> initial_sorted_elements([1, 3, 5, 4, 1, 9])
3
>>> initial_sorted_elements([5, 9, 1, 1, 3, 4])
2
>>> initial_sorted_elements([4, 9, 1, 5, 1, 3])
2
>>> initial_sorted_elements([1, 1, 4, 9, 5, 3])
4
"""
sorted_end = is_sorted_until(values.begin(), values.end())
return distance(values.begin(), sorted_end)
def sort_ints(vector[int] values):
"""Test sort using the default operator<.
>>> sort_ints([5, 7, 4, 2, 8, 6, 1, 9, 0, 3])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
sort(values.begin(), values.end())
return values
def sort_ints_reverse(vector[int] values):
"""Test sort using a standard library comparison function object.
>>> sort_ints_reverse([5, 7, 4, 2, 8, 6, 1, 9, 0, 3])
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
"""
sort(values.begin(), values.end(), greater[int]())
return values
def partial_sort_ints(vector[int] values, int k):
"""
Test partial_sort using the default operator<.
>>> partial_sort_ints([4, 2, 3, 1, 5], 2)[:2]
[1, 2]
"""
partial_sort(values.begin(), values.begin() + k, values.end())
return values
def partial_sort_ints_reverse(vector[int] values, int k):
"""
Test partial_sort using a standard library comparison function object.
>>> partial_sort_ints_reverse([4, 2, 3, 1, 5], 2)[:2]
[5, 4]
"""
partial_sort(values.begin(), values.begin() + k, values.end(), greater[int]())
return values
def partial_sort_ints2(vector[int] values, int k):
"""
Test partial_sort_copy using the default operator<.
>>> partial_sort_ints2([4, 2, 3, 1, 5], 2)
[1, 2]
"""
output = vector[int](2)
partial_sort_copy(values.begin(), values.end(), output.begin(), output.end())
return output
def partial_sort_ints_reverse2(vector[int] values, int k):
"""
Test partial_sort_copy using a standard library comparison function object.
>>> partial_sort_ints_reverse2([4, 2, 3, 1, 5], 2)
[5, 4]
"""
output = vector[int](2)
partial_sort_copy(values.begin(), values.end(), output.begin(), output.end(), greater[int]())
return output
cdef extern from *:
"""
struct Employee
{
Employee() = default;
Employee(int age, std::string name): age(age), name(name) {}
int age;
std::string name; // Does not participate in comparisons
};
bool operator<(const Employee& lhs, const Employee& rhs)
{
return lhs.age < rhs.age;
}
"""
cppclass Employee:
Employee()
Employee(int, string)
int age
string name
cdef bool Employee_greater(const Employee& lhs, const Employee& rhs):
return lhs.age > rhs.age
def test_stable_sort():
"""
Test stable_sort using cppreference example.
>>> test_stable_sort()
32, Arthur
108, Zaphod
108, Ford
108, Zaphod
108, Ford
32, Arthur
"""
cdef vector[Employee] employees
employees.push_back(Employee(108, <string>b"Zaphod"))
employees.push_back(Employee(32, <string>b"Arthur"))
employees.push_back(Employee(108, <string>b"Ford"))
stable_sort(employees.begin(), employees.end())
for e in employees:
print("%s, %s" % (e.age, <str>(e.name).decode("ascii")))
stable_sort(employees.begin(), employees.end(), &Employee_greater)
for e in employees:
print("%s, %s" % (e.age, <str>(e.name).decode("ascii")))
def second_smallest(vector[int] values):
"""
Test nth_element using the default operator<.
>>> second_smallest([5, 6, 4, 3, 2, 6, 7, 9, 3])
3
"""
nth_element(values.begin(), values.begin() + 1, values.end())
return values[1]
def second_largest(vector[int] values):
"""
Test nth_element using a standard library comparison function object.
>>> second_largest([5, 6, 4, 3, 2, 6, 7, 9, 3])
7
"""
nth_element(values.begin(), values.begin() + 1, values.end(), greater[int]())
return values[1]
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# tag: cpp # tag: cpp
from libcpp cimport bool from libcpp cimport bool
from libcpp.algorithm cimport make_heap, sort_heap, sort, partial_sort from libcpp.algorithm cimport make_heap, sort_heap
from libcpp.vector cimport vector from libcpp.vector cimport vector
...@@ -28,33 +28,3 @@ def heapsort(l, bool reverse=False): ...@@ -28,33 +28,3 @@ def heapsort(l, bool reverse=False):
sort_heap(v.begin(), v.end()) sort_heap(v.begin(), v.end())
return v return v
def partialsort(l, int k, reverse=False):
"""
>>> partialsort([4, 2, 3, 1, 5], k=2)[:2]
[1, 2]
>>> partialsort([4, 2, 3, 1, 5], k=2, reverse=True)[:2]
[5, 4]
"""
cdef vector[int] v = l
if reverse:
partial_sort(v.begin(), v.begin() + k, v.end(), &greater)
else:
partial_sort(v.begin(), v.begin() + k, v.end())
return v
def stdsort(l, reverse=False):
"""
>>> stdsort([3, 2, 1, 4, 5])
[1, 2, 3, 4, 5]
>>> stdsort([3, 2, 1, 4, 5], reverse=True)
[5, 4, 3, 2, 1]
"""
cdef vector[int] v = l
if reverse:
sort(v.begin(), v.end(), &greater)
else:
sort(v.begin(), v.end())
return v
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment