создать массив на основе группировки (и условий) из массива - PullRequest
0 голосов
/ 08 мая 2020

Итак, у меня есть следующий массив (структурированный как Array{Tuple{Int,Float64,Int,Int},1}, но он также может быть массивом массивов), где первым элементом кортежа является ID, а вторым - число, указывающее стоимость. Что я хочу сделать, так это сгруппировать по ID, а затем взять разницу в стоимости между самой дешевой и второй по стоимости для такой ID, если нет второй стоимости, разница в стоимости должна быть typemax(Float64) -firstcost. Что касается третьего и четвертого элементов Tuple, я хочу сохранить элементы firstcost (или минимальную стоимость в этом смысле). Пример того, что у меня есть

(1, 223.2, 2, 2)
(1, 253.2, 3, 2)
(2, 220.0, 4, 6)
(3, 110.0, 1, 4)
(3, 100.0, 3, 8)

Пример того, что я хочу:

(1, 30.0, 2, 2)
(2, typemax(Float64)-220.0, 4, 6)
(3,10.0, 3, 8)

Ответы [ 2 ]

1 голос
/ 08 мая 2020

Это один из способов:

A = [(1, 223.2, 2, 2), (1, 253.2, 3, 2), (2, 220.0, 4, 6), (3, 110.0, 1, 4), (3, 100.0, 3, 8)]

function f(a)
    aux(b::Vector) = (b[1][1], (length(b) == 1 ? typemax(Float64) : b[2][2]) - b[1][2], b[1][3:4]...)
    sort([aux(sort(filter(x -> x[1] == i, a))) for i in Set(map(first, a))])
end

@show f(A)
0 голосов
/ 09 мая 2020

Там SplitApplyCombine.jl, который реализует (что неудивительно) логику разделения-применения-объединения c, подобную той, что есть в DataFrames. Это пример, в котором я бы держался подальше от простых однострочных / коротких решений и писал бы вещи более подробно, чтобы сделать код читаемым и понятным, если кто-то другой (или вы сами через несколько месяцев!) Прочитает его:

julia> tups = [(1, 223.2, 2, 2)
       (1, 253.2, 3, 2)
       (2, 220.0, 4, 6)
       (3, 110.0, 1, 4)
       (3, 100.0, 3, 8)]
5-element Array{Tuple{Int64,Float64,Int64,Int64},1}:
 (1, 223.2, 2, 2)
 (1, 253.2, 3, 2)
 (2, 220.0, 4, 6)
 (3, 110.0, 1, 4)
 (3, 100.0, 3, 8)

julia> using SplitApplyCombine

julia> function my_fun(x) # function to apply
           if length(x) == 1
               return (x[1][1], typemax(Float64) - x[1][2], x[1][3], x[1][4])
           else
               return (x[1][1], -diff(sort(getindex.(x, 2), rev = true)[1:2]), x[1][4])
           end
       end
my_fun (generic function with 1 method)

julia> [my_fun(x) for x in group(first, tups)] # apply function group wise
3-element Array{Tuple{Int64,Any,Int64,Vararg{Int64,N} where N},1}:
 (2, Inf, 4, 6)
 (3, [10.0], 4)
 (1, [30.0], 2)

Если производительность вызывает беспокойство, вы можете подумать о my_fun и провести некоторое профилирование, чтобы увидеть, можно ли и как его улучшить - единственное, что я здесь сделал, это использовал diff чтобы вычесть первый из второго элемента отсортированного массива, чтобы избежать двойной сортировки.

...