【问题标题】:Sort array of Dicts by multiple keys, in Julia在 Julia 中按多个键对字典数组进行排序
【发布时间】:2018-04-09 01:52:29
【问题描述】:

我有一大堆Dicts,看起来都像这样

{
  "id": 12345,
  "user_id": "6789",
  "question_id": "some_question_id",
  "correct": "true",
  "actions": "...",
  "consequentiality": 0,
  "timestamp": 1505123456.000
}

我需要按(question_id, user_id, id, consequentiality) 对它们进行排序,question_id 移动最慢,consequentiality 移动更快——有点像分组和子分组,如果你愿意的话,但我需要对有序的进行交换在某些情况下排列,其中大多数往往发生在组之间。我一直在玩Base.sort,将不同的函数传递给bylt。我想出的最好的方法是将多种排序组合在一起,并将不同的键传递给每个 by 子句,类似于

sort(sort(sort(sort(df, by=x->x["question_id"]), by=x->x["user_id"] ...

你明白了。到目前为止,即使使用MergeSort 之类的稳定算法,我也无法达到令人满意的稳定排序。

帮助?

EDITby 子句中使用元组有意义吗?但是,如何反转非数字元素的顺序?

【问题讨论】:

  • 试试sort(df, by=x->getindex.(x,("question_id", "user_id", "id", "consequentiality")))
  • 关于反转非数字值的顺序,这可能需要在lt= 参数中使用自定义小于函数。
  • 要对非数字用户名字段进行反向排序,例如,您可以这样做:sort(df, lt=(x,y)->lexless((x["question_id],false,x["id"]),(y["ques‌​tion_id],x["username"]>y["username"],y["id"‌​])))。这首先按question_id 排序,然后按username 反向排序,然后按id 排序(诀窍是将false 与username 上的大于表达式进行比较,从而颠倒顺序)
  • 好的,通过您的最新编辑(交换真假并更改比较符号),我可以让一切井井有条。我很困惑,因为"id" 出现错误,我无法扭转它。
  • 现在,任务是让它看起来更漂亮,检查效率,也许定义一个函数来让它更干净。

标签: arrays sorting dictionary julia


【解决方案1】:

这里演示了在 cmets 中使用 lt=... 清理解决方案的方法。请注意,这仅适用于元组,因为它为元组重新定义了 isless。如果有热情,也许可以将这样的东西合并到 Julia 或某个包中。

julia> struct RevNext
       end

julia> import Base: isless

julia> function isless(t1::Tuple, t2::Tuple)
           n1, n2 = length(t1), length(t2)
           reverse = false
           for i = 1:min(n1, n2)
               a, b = t1[i], t2[i]
               if !isequal(a, b)
                   return reverse ? isless(b, a) : isless(a,b)
               else
                   reverse = isa(a,RevNext)
               end
           end
           return n1 < n2
       end
WARNING: Method definition isless(Tuple, Tuple) ...
isless (generic function with 53 methods)

为了使用它,我们写sort(M,by=x-&gt;(x[:b], RevNext(), x[:a]))。随机生成向量M的示例:

julia> M = [Dict(:a=>rand(),:b=>rand(Bool)) for i=1:10]
10-element Array{Dict{Symbol,Any},1}:
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.735352),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.537437),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.314947),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.9723),Pair{Symbol,Any}(:b, false))  
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.605042),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.256509),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.133487),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.320249),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.409549),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.421471),Pair{Symbol,Any}(:b, true)) 

julia> sort(M,by=x->(x[:b], RevNext(), x[:a]))
10-element Array{Dict{Symbol,Any},1}:
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.9723),Pair{Symbol,Any}(:b, false))  
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.320249),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.256509),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.133487),Pair{Symbol,Any}(:b, false))
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.735352),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.605042),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.537437),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.421471),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.409549),Pair{Symbol,Any}(:b, true)) 
 Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 0.314947),Pair{Symbol,Any}(:b, true)) 

【讨论】:

  • 我认为我更喜欢其他解决方案。两者都有点笨拙,但另一个更紧凑,并且和这个一样通用(不是很)——至少它不涉及改变相邻参数语义的参数。最初,我希望sortrev 参数接受一个布尔元组来反转by 中传递的元组。
猜你喜欢
  • 2016-04-17
  • 1970-01-01
  • 2016-03-03
  • 2018-12-22
  • 1970-01-01
  • 2021-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多