嵌套循环最有效的数据结构?

问题描述

我正在遍历第一个文件中的每一行(总共 3000 行)以在第二个文件中逐行查找它对应的标签(大约 200 万行;47 MB​​)

目前,我有一个嵌套循环结构,外循环抓取一行(转换为列表),内循环遍历 200 万行(逐行):

for row in read_FIMO: #read_FIMO is first file; 3000 lines long
     with open("chr8labels.txt") as label: #2 million lines long  
         for line in csv.reader(label,delimiter="\t"): #list
            for i in range(int(row[3]),int(row[4])):  
                if i in  range((int(line[1])-50),int(line[1])):#compare the ranges in each list
                    line1=str(line)  
                    row1=str(row)  
                    outF.append(row1+"\t"+line1)

-我意识到这是非常低效的,但我需要找到第一个范围与另一个文件的范围重叠的所有实例 - 逐行读取每个文件是最快的方式吗?如果没有,整个文件的最佳数据结构是什么
- 行应该在列表之外的不同数据结构中吗?

如果您有任何反馈,谢谢!

旁白:目的是在其他文件的范围内找到数字时标记一个数字范围(长话短说;可能不相关?)

解决方法

您的目标似乎是找出一个范围 (row[3] to row[4]) 是否与另一个范围 (line[1]-50 to line[1]) 重叠。为此,只要 line[1]-50row[3] 位于其他范围内就足够了。这消除了第三个嵌套循环。

另外,将 200 万行的文件排序一次,然后使用 3000 行循环中的排序列表进行二分查找,从 O(nm) 算法切割到 O(nlogm) ) 一个。

(我的 Python 远非完美,但这应该能让你朝着正确的方向前进。)

with open("...") as label:
  reader = csv.reader(label,delimiter="\t")
  lines = list(reader)
  lines.sort(key=lambda line: int(line[1]))

for row in read_FIMO:
  # Find the nearest,lesser value in lines smaller than row[3]
  line = binary_search(lines,int(row[3]))

  # If what you're after is multiple matches,then
  # instead of getting a single line,get the smallest and 
  # largest indexes whose ranges overlap (which you can do with a 
  # binary search for row[3] and row[4]+50)
  # e.g.,# smallestIndex = binary_search(lines,int(row[3]))
  # largestIndex = binary_search(lines,int(row[4])+50)
  # for index in range(smallestIndex,largestIndex+1):

  lower1 = int(line[1] - 50)
  lower2 = int(row[3])
  upper1 = int(line[1])
  upper2 = int(row[4])
  if (lower1 > lower2 and lower1 < upper1) or (lower2 > lower1 and lower2 < upper2):
    line1=str(line)  
    row1=str(row)  
    outF.append(row1+"\t"+line1)

,

我认为有效的方法是......

  1. 首先遍历目标文件并记录所有标签 到字典哈希。 [LabelName] -> [Line number]

  2. 遍历源代码的每一行并从源代码中查找该行 字典并打印(如果找不到,则打印其他内容)

注意事项/提示

  • 我认为以上将是 O(n)
  • 您也可以先浏览源文件,然后录制,然后再浏览目标文件。这将创建一个更小的字典(并使用更少的内存),但输出可能不是您想要的顺序。 (较小的数据集通常具有更好的缓存命中率,所以这就是我提出这一点的原因。)
  • 另外,仅仅因为你提到了most efficient,如果你想变得疯狂,我会尝试跳过一行一行的处理,并且像输入一个大字符串一样遍历输入。搜索新行字符 + 空格 + 标签名称。使用这种技巧取决于输入数据的样子。如果“csv.reader”已经按行解析,那么这不会很好。此外,您可能需要一种具有更多控制权的低级语言来执行此方法。 (注意:这个提示有 90% 的可能性只会把你带到一个无处可去的兔子洞)