在ruby中,如何使用id键重新排列对象数组,将数组的新顺序指定为数组?

时间:2019-05-17 12:00:10

标签: arrays json ruby

我有一个对象,其数组如下所示:

some_object = {
  some_array: [
    { id: "foo0" },
    { id: "foo1" },
    { id: "foo2" },
    { id: "foo3" },
  ]
}

我有另一个数组的输入,我想在

中重新排列该数组
target_order = [
  { id: "foo0", new_position: 3 },
  { id: "foo3", new_position: 0 },
  { id: "foo1", new_position: 2 },
  { id: "foo2", new_position: 1 }
]

如何使用第二个target_order数组修改第一个some_object[:some_array]的顺序?

4 个答案:

答案 0 :(得分:1)

我建议您将sort_by与自定义块一起使用,该块可以找到项目在新数组中的位置。

new_array = some_object[:some_array].sort_by do |item|
  order = target_order.detect { |order| order[:id] == item[:id] }
  next unless order

  order[:new_position]
end

这将返回以下值。

=> [{:id=>"foo2"}, {:id=>"foo1"}, {:id=>"foo0"}, {:id=>"foo3"}]

其他注意事项

也许您想给每个项目一个列表中的位置,而不仅仅是对其进行排序。例如

target_order = [
  { id: "foo0", new_position: 0 },
  { id: "foo1", new_position: 2 }
]

会给

=> [{ id: "foo0" }, nil, { id: "foo1" }]

为此,您应该使用each_with_object而不是sort_by

new_array = target_order.each_with_object([]) do |order, memo|
  item = some_object[:some_array].detect { |item| item[:id] == order[:id] }
  next unless item

  memo[order[:new_position]] = item
end

答案 1 :(得分:0)

简单起见,这就是我要做的...

temp_arr = []

target_order.each do |o|
  x = some_json_object[:some_array].find { |i| o[:id] == i[:id] }
  temp_arr[o[:new_position] - 1] = x
end

some_json_object = {
  "some_array": temp_arr
}

答案 2 :(得分:0)

如果some_arraytarget_order元素之间存在一对一的对应关系,也许您可​​以直接进行分配,例如:

some_object[:some_array] = target_order.sort_by{ |h| h[:new_position] }.map { |h| h.delete_if { |k, _| k == :new_position } }

所以,您最终会得到

some_object #=> {:some_array=>[{:id=>"foo3"}, {:id=>"foo2"}, {:id=>"foo1"}, {:id=>"foo0"}]}

答案 3 :(得分:0)

不需要排序,排序具有O(n * log(n))的时间复杂度。这是一个O(n)解。

from os import system, listdir, path
import codecs
FILE = open('C:\\Users\\Admin\\Desktop\\Test\\Result.txt', 'w') 
    desktop_dir =       path.join('C:\\Users\\Admin\\Desktop\\test\\')  
for fn in listdir(desktop_dir):
    fn_w_path = path.join(desktop_dir, fn)
    if path.isfile(fn_w_path):
        with open(fn_w_path, "r") as filee:  
            for line in filee.readlines():  
                for word in line.lower().split():
                    if word in {'James',
                                'Tim',
                                'Tom',
                                'Ian',
                                'William',
                                'Dennis',}:  
                        FILE.write(word + "\n")
FILE.close()

import os
import shutil

for root, dirs, files in os.walk("test_dir1", topdown=False):
    for name in files:
        current_file = os.path.join(root, name)
        destination = current_file.replace("test_dir1", "test_dir2")
        print("Found file: %s" % current_file)
        print("File copy to: %s" % destination)
        shutil.copy(current_file, destination)

请注意,这里没有引用{ some_array: target_order.each_with_object([]) { |h,a| a[h[:new_position]] = h.slice(:id) } } #=> {:some_array=>[{:id=>"foo3"}, {:id=>"foo2"}, {:id=>"foo1"}, {:id=>"foo0"}]}

如果要some_object进行修改:

some_object

使用Enumerable#sort_by,虽然效率较低,但可以这样写:

some_object[:some_array] = target_order.each_with_object([]) { |h,a|
  a[h[:new_position]] = h.slice(:id) }
some_object
  #=> {:some_array=>[{:id=>"foo3"}, {:id=>"foo2"}, {:id=>"foo1"}, {:id=>"foo0"}]}