我有2个包含日期和数据的列表。每个列表按照序列号所指示的顺序排列。现在我需要将两个列表合并在一起,并按正确顺序保存所有内容。
例如:
列表A
20101001 A数据1 seq1
20101001 A数据2 seq2
20101005 A数据3 seq3清单B
20101001 B数据1 seq1
20101003 B数据2 seq2等...
我需要新列表看起来像这样:
20101001 A数据1 seq1
20101001 A数据2 seq2
20101001 B数据1 seq3
20101003 B数据2 seq4
20101005 A数据3 seq5
我想到的两件事是将列表合并在一起并在将它们插入数据库之前应用序列号,或者我可以使用当前序列将它们插入到数据库中并再次将它们拉回来将它们合并在一起,但是这似乎是一个额外的步骤和kludgy。
有关最佳方式的任何想法吗?
答案 0 :(得分:5)
假设您的列表位于Ruby Arrays中,并且列表中的对象定义了属性(例如obj.sequence_number),则对列表进行合并和排序的一种方法是:
首先将列表合并为联合:
@merged_list = @list_a | @list_b
然后使用适当的排序规则对merged_list进行排序:
@merged_list.sort! {|a, b| a.date <=> b.date # or whatever your sorting rule is... }
编辑:
合并后的数组排序后,您可以重新定义sequence_number:
@merged_list.each_with_index {|obj, index| obj.sequence_number = "seq#{index+1}"}
编辑:
如果列表中的对象本身只是简单的数组,则同样适用:
@merged_list.sort! {|a, b| a[0] <=> b[0] # or whatever your sorting rule is... }
@merged_list.each_with_index {|obj, index| obj[2] = "seq#{index+1}"}
答案 1 :(得分:0)
试试这个:
(listA + listB).sort!{|a, b| a.sequence_no <=> b.sequence_no}
答案 2 :(得分:0)
这是一种用于在或多或少的线性时间内合并任意数量的排序列表的算法:
def merge_sorted(*lists)
# the lists will be modified, so make (shallow) copies
lists = lists.map(&:dup)
result = []
loop do
# ignore lists that have been exhausted
lists = lists.reject(&:empty?)
# we're done if all lists have been exhausted
break if lists.empty?
# find the list with the smallest first element
top = lists.inject do |candidate, other|
candidate.first < other.first ? candidate : other
end
result << top.shift
end
result
end
list1 = [1, 2, 5, 6, 9]
list2 = [2, 3, 4, 11, 13]
list3 = [1, 2, 2, 2, 3]
p merge_sorted(list1, list2, list3)
# => [1, 1, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 9, 11, 13]
对于每次迭代,它会找到具有最小第一个元素的列表,并将此元素从其中移到结果列表中。它会执行此操作,直到所有列表都为空。
我说或多或少线性时间,因为它实际上是O(n×m),其中n是列表数,m是列表中元素的总数,但我认为这可以安全在大多数情况下,简化为O(m),因为与m相比,n会很小。
答案 3 :(得分:0)
这使用with_index
这是向迭代器添加索引值的好方法:
result = (list_a + list_b).sort_by { |a| a[0 .. -2] }.map.with_index { |a, i| a[0 .. -2] + (1 + i).to_s }
puts result
# >> 20101001 A data 1 seq1
# >> 20101001 A data 2 seq2
# >> 20101001 B data 1 seq3
# >> 20101003 B data 2 seq4
# >> 20101005 A data 3 seq5
以下是基准测试的一些变体:
require 'benchmark'
list_a = [
'20101001 A data 1 seq1',
'20101001 A data 2 seq2',
'20101005 A data 3 seq3'
]
list_b = [
'20101001 B data 1 seq1',
'20101003 B data 2 seq2'
]
# #1
result = (list_a + list_b).sort_by { |a| a[0 .. -2] }.map.with_index { |a, i| a[0 .. -2] + (1 + i).to_s }
result # => ["20101001 A data 1 seq1", "20101001 A data 2 seq2", "20101001 B data 1 seq3", "20101003 B data 2 seq4", "20101005 A data 3 seq5"]
# #2
result = (list_a + list_b).map{ |r| r[0 .. -2] }.sort.map.with_index { |a, i| a + (1 + i).to_s }
result # => ["20101001 A data 1 seq1", "20101001 A data 2 seq2", "20101001 B data 1 seq3", "20101003 B data 2 seq4", "20101005 A data 3 seq5"]
# #3
i = 0
result = (list_a + list_b).map{ |r| r[0 .. -2] }.sort.map { |a| i += 1; a + i.to_s }
result # => ["20101001 A data 1 seq1", "20101001 A data 2 seq2", "20101001 B data 1 seq3", "20101003 B data 2 seq4", "20101005 A data 3 seq5"]
# #4
i = 0; result = (list_a + list_b).sort.map { |a| i += 1; a[-1] = i.to_s; a }
result # => ["20101001 A data 1 seq1", "20101001 A data 2 seq2", "20101001 B data 1 seq3", "20101003 B data 2 seq4", "20101005 A data 3 seq5"]
n = 75000
Benchmark.bm(7) do |x|
x.report('#1') { n.times { (list_a + list_b).sort_by { |a| a[0 .. -2] }.map.with_index { |a, i| a[0 .. -2] + (1 + i).to_s } } }
x.report('#2') { n.times { (list_a + list_b).map{ |r| r[0 .. -2] }.sort.map.with_index { |a, i| a + (1 + i).to_s } } }
x.report('#3') { n.times { i = 0; (list_a + list_b).map{ |r| r[0 .. -2] }.sort.map { |a| i += 1; a + i.to_s } } }
x.report('#4') { n.times { i = 0; (list_a + list_b).sort.map { |a| i += 1; a[-1] = i.to_s } } }
end
# >> user system total real
# >> #1 1.150000 0.000000 1.150000 ( 1.147090)
# >> #2 0.880000 0.000000 0.880000 ( 0.880038)
# >> #3 0.720000 0.000000 0.720000 ( 0.727135)
# >> #4 0.580000 0.000000 0.580000 ( 0.572688)
基准测试很好。