I have a array like the following:
julia> list = [(x, rand(0:9), rand(0:9)) for x in 1:5]
5-element Array{Tuple{Int64,Int64,Int64},1}:
(1, 7, 2)
(2, 1, 3)
(3, 4, 7)
(4, 4, 8)
(5, 8, 3)
I'd like to find the element in that list whose third value is greatest. If I just do maximum(list), it uses the default (lexicographic) ordering, which is not what I want:
julia> maximum(list)
(5, 8, 3)
I can use a custom by transformation/predicate if I sort the entire list:
julia> sort(list, by=x->x[3], rev=true)
5-element Array{Tuple{Int64,Int64,Int64},1}:
(4, 4, 8)
(3, 4, 7)
(2, 1, 3)
(5, 8, 3)
(1, 7, 2)
But that does a lot of extra work — all I need is that first value — but it appears maximum does not support the by keyword argument:
julia> maximum(list, by=x->x[3])
ERROR: MethodError: no method matching maximum(::Array{Tuple{Int64,Int64,Int64},1}; by=var"#21#22"())
And if I use the "transforming" first argument function, I only get the third value back:
julia> maximum(x->x[3], list)
8
I want the entire element — (4, 4, 8) in this case. How can I do this?
While maximum does not support by keyword, it does support a "transformer" function. In this particular case, we can find the maximum of the reversed elements, and then reverse it back:
julia> reverse(maximum(reverse, list))
(4, 4, 8)
More generally, you can use the sorting infrastructure (with all its fancy by transformers and custom lt comparisons) without actually sorting the entire list with partialsort:
julia> partialsort(list, 1, by=x->x[3], rev=true)
(4, 4, 8)
This isn't quite as efficient but it's far more capable — and it saves quite a bit over sorting the entire thing. With a larger vector:
julia> using BenchmarkTools
julia> list = [(x, rand(0:9), rand(0:9)) for x in 1:10_000];
julia> @btime reverse(maximum(reverse, $list));
7.833 μs (0 allocations: 0 bytes)
julia> @btime partialsort($list, 1, by=x->x[3], rev=true);
37.772 μs (3 allocations: 234.48 KiB)
julia> @btime sort($list, by=x->x[3], rev=true);
339.570 μs (5 allocations: 351.81 KiB)
Another possibility is to use sortperm to get the permutation indices of the reduced array (only containing the keys by which you want to sort), and then use those indices to sort the full array:
a = [(x, rand(0:9), rand(0:9)) for x in 1:5]
perm = sortperm(a, by=x->x[3], rev=true)
b = a[perm]
Or in case you're only interested in the maximum, use
b_max = a[perm[1]]
Or
i_max = findmax(map(x->x[3], a)[2]
b_max = a[i_max]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With