【问题标题】:How to combine two list that contain intervals如何组合两个包含间隔的列表
【发布时间】:2011-08-17 05:35:07
【问题描述】:

我有列表 1 和 2,我想获得列表 3。如果有人可以建议 python 或 awk 脚本,那就太好了。

清单 1 100-160 B 200-500 C 800-1500 D 1600-2000 E 2500-3000 清单 2 150 600 900 1700 2400 清单 3 100-160 150 B 200-500 C 800-1500 900 D 1600-2000 1700 E 2500-3000

【问题讨论】:

  • 只有当 list2 的值在 list1 的值之间时,它才会从列表 2 中添加?
  • 请明确说明合并和排序结果的逻辑。我已经从这个问题中删除了ruby 标签,因为您没有要求使用 Ruby 的解决方案。如果您愿意,请编辑您的问题并这样说。
  • 您是否需要一个 Ruby 脚本,但忘记将其添加到问题中,或者您是否不小心添加了 ruby​​ 标签?
  • 您是说您有一些包含这些列表的文本(例如,在一个文件中)并且您想要包含列表 3 的文本,可能在另一个文件中?我不清楚我们在谈论什么“数据类型”,因为您对编程语言不了解。
  • 列表 1 包含区间,列表 2 包含一些值(不是全部)在第一个列表的区间内。如果他们这样做(第二个列表的值),我想将它们与第一个匹配。第二个列表中可能有多个值落在第一个列表的一个区间内。

标签: python linux awk


【解决方案1】:

这是一个例子。它期望在命令行上传递两个文件名。

import sys

if len(sys.argv) != 3:
    print 'parameters: list1 list2'
    sys.exit(1)

list1 = []
for line in file(sys.argv[1]):
    fields = line.split()
    f1 = fields[0]
    f2, f3 = fields[1].split('-')
    list1.append((f1, int(f2), int(f3), [], ))

for line in file(sys.argv[2]):
    value = int(line)
    for name, lb, ub, values in list1:
        if value >= lb and value <= ub:
            values.append(str(value))

for name, lb, ub, values in list1:
    if values: vals = ','.join(values)
    else: vals = ''
    print '%s %d-%d %s' % (name, lb, ub, vals, )

【讨论】:

  • 感谢 FuzzyWuzzy。这很好用,除了我必须将原始名称 Solyc08g007690.1.1 更改为 1、2、3..
【解决方案2】:

您可以从列表 1 中创建一个包含区间的字典,然后循环遍历它以查看列表 2 中的任何值是否在范围内。例如,

list1 = {"A": [100, 160], "B": [200, 500], "C": [800, 1500],
         "D": [1600, 2000], "E": [2500,3000]}

list2 = [150, 600, 900, 1700, 2400]

for key, val in list1.iteritems():
    for num in list2:
        if num in range(val[0], val[1]):
            val.append(num)

for key, val in sorted(list1.iteritems()):
    print key, ":", val

【讨论】:

  • 一个问题是他将失去列表 1 中的排序(python 将随机化键的顺序)。当我运行它时,它会出现“A、C、B、E、D”。
  • 如果范围比较大,最好使用xrange() 而不是range()
  • 好吧,xrange 真的只适用于非常大的数字,其中内存是一个问题。就像试图计算 10 亿以下的所有素数一样。 Xrange 会对此有好处。对于这样的事情,范围真的很好。要解决非排序问题,我只需要在字典循环打印时快速更改一些内容以对键进行排序。
  • 实际上,为此你不应该使用 range 或 xrange,只需使用 if val[0]&lt;=num&lt;val[1]
  • 我在 2 分钟内把这个放在一起!它没有优化:O.
【解决方案3】:

你可以在 Python 中做这样的事情:

L1 = [(100, 160), (200, 500), (800, 1500), (1600, 2000), (2500, 3000)]
L2 = [150, 600, 900, 1700, 2400]
L3 = [((a, b), [i for i in L2 if a<=i<b]) for (a, b) in L1]

如果您需要,将数据解析为该结构很容易(并将其打印回来),但我会等到您解释数据的格式以及您需要的格式,因为我有感觉会有问题。

【讨论】:

  • 列表一和二在两个不同的文件中,我想用列表 3 创建第三个文件。很抱歉造成混淆。
  • 好吧,@FuzzyWuzzy 几乎完成了我在此期间要做的事情,所以请不要更改我的答案。
【解决方案4】:

只需在命令行上执行即可。到目前为止,这是唯一的 awk 解决方案:

 paste list1 list2|awk '{split($2,a,"-");
                           if($3>a[1] && $3<a[2])
                           {h=$3}
                           else
                           {h=""};
                           print $1,$2,h}'

A 100-160 150
B 200-500
C 800-1500 900
D 1600-2000 1700
E 2500-3000

【讨论】:

    【解决方案5】:

    不确定是否需要 Ruby,但这里有一个快速通道:

    list1 = %w[ A 100-160 B 200-500 C 800-1500 D 1600-2000 E 2500-3000 ]
    list2 = %w[ 150, 600, 900, 1700, 2400 ]
    
    list3 = []
    
    list1.each_slice(2) do |char, range|
      min_range, max_range = range.split('-').map{ |i| i.to_i }
      l2 = list2.shift
      case l2.to_i
      when min_range..max_range
        list3 << [ char, range, l2 ]
      else
        list3 << [ char, range ]
      end
    end
    
    require 'pp'
    pp list3
    
    >> [["A", "100-160", "150,"],
    >>  ["B", "200-500"],
    >>  ["C", "800-1500", "900,"],
    >>  ["D", "1600-2000", "1700,"],
    >>  ["E", "2500-3000"]]
    

    【讨论】:

      【解决方案6】:

      您可以使用可迭代的工具来编写它。不太可读,但这有效。写起来肯定很有趣!

      from itertools import chain
      
      nameranges = ['A', '100-160', 'B', '200-500', 'C', '800-1500', 'D', '1600-2000', 
                    'E', '2500-3000']
      
      values = [150, 600, 900, 1700, 2400]
      z = zip(nameranges[0::2], ( map(int, x.split("-")) for x in nameranges[1::2]))
      f = list(chain(* (map(lambda x, y: (x[0][0], x[1][0], x[1][1], y) 
                     if x[1][0]<=y<=x[1][1] else (x[0], x[1][0], x[1][1]), 
                     z, values))))
      # print f
      #['A', 100, 160, 150, 'B', 200, 500, 'C', 800, 1500, 900, 'D', 1600, 2000, 1700, 
      # 'E', 2500, 3000]
      

      【讨论】:

        【解决方案7】:

        这是我的看法。由于您没有指定,我只是弥补了解析和打印位。

        list_1 = ['A\t100-160', 'B\t200-500', 'C\t800-1500', 'D\t1600-2000', 'E\t2500-3000']
        list_2 = [150, 600, 900, 1700, 2400]
        
        for range in list_1:
            # parse the input (this may be different, but you didn't specify)
            lower_bound, upper_bound = range.split('\t')[1].split('-')  # this is a bit fragile
            lower_bound = int(lower_bound)
            upper_bound = int(upper_bound)
        
            # make sure lower_bound is less than upper_bound
            if upper_bound < lower_bound:
                (lower_bound, upper_bound) = (upper_bound, lower_bound)
        
            # loop over list 2 and see if any fall into the current range
            items_in_range = [str(number) for number in list_2 if lower_bound <= number < upper_bound]
        
            # output List 3
            print range + '\t' + ','.join(items_in_range)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-19
          • 1970-01-01
          • 1970-01-01
          • 2011-11-09
          • 2020-12-26
          • 2014-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多