0

初期識別子列、開始値、および終了値を持つ 2 つのファイルを比較しています。2 番目のファイルには、対応する識別子と別の値の列が含まれています。

元。

ファイル 1:

A     200     900
A     1000    1200
B     100     700
B     900     1000

ファイル 2:

A     103
A     200
A     250
B     50
B     100
B     150

出力が次のようになるように、最初のファイルで見つかった範囲内に含まれる 2 番目のファイルからすべての値を検索したいと思います。

A     200
A     250
B     100
B     150

今のところ、範囲のリストを含む最初のファイルから辞書を作成しました。

if Identifier in Dictionary:
    Dictionary[Identifier].extend(range(Start, (End+1)))
else:
    Dictionary[Identifier] = range(Start, (End+1))

次に、2 番目のファイルを調べて、範囲の辞書内で値を検索します。

if Identifier in Dictionary:
    if Value in Dictionary[Identifier]:
    OutFile.write(Line + "\n")

最適ではありませんが、これは比較的小さなファイルでは機能しますが、いくつかの大きなファイルがあり、このプログラムは非常に非効率的であることが証明されています. プログラムがより高速に実行されるように、プログラムを最適化する必要があります。

4

5 に答える 5

2
from collections import defaultdict
ident_ranges = defaultdict(list)
with open('file1.txt', 'r') as f1
    for row in f1:
        ident, start, end = row.split()
        start, end = int(start), int(end)
        ident_ranges[ident].append((start, end))
with open('file2.txt', 'r') as f2, open('out.txt', 'w') as output:  
    for line in f2:
        ident, value = line.split()
        value = int(value)
        if any(start <= value <= end for start, end in ident_ranges[ident]):
            output.write(line)

: a を使用するdefaultdictと、最初にキーの存在を確認せずに範囲を辞書に追加できます。を使用anyすることで、レンジチェックを短絡することができます。連鎖比較を使用することは、Python の構文上の優れたショートカットです ( start <= value <= end)。

于 2013-03-13T18:05:26.263 に答える
0

範囲が広く、問題は基本的に単なる比較の集まりであるため、範囲全体よりも開始/終了タプルを格納する方がほぼ確実に高速です(特に、現在の数値のほとんどが2つが重なっている場合の範囲)。

# Building the dict
if not ident in d:
    d[ident] = (lo, hi)
else:
    old_lo, old_hi = d[ident]
    d[ident] = (min(lo, old_lo), max(hi, old_hi))

次に、比較は次のようになります。

# comparing...
if ident in d:
    if d[ident][0] <= val <= d[ident][1]:
        outfile.write(line+'\n')

を個別にチェックしない場合、この両方の部分が高速になりますif ident in d。Python辞書は素晴らしくて速いので、そもそもそれを呼び出すだけです。辞書にデフォルトを提供する機能があるので、それを使用してください。私はこれや何かをベンチマークしてスピードアップが何であるかを確認していませんが、あなたは確かにいくつかを得るでしょう、そしてそれは確かに機能します:

# These both make use of the following somewhat silly hack:
# In Python, None is treated as less than everything (even -float('inf))
# and empty containers (e.g. (), [], {}) are treated as greater than everything.
# So we use the tuple ((), None) as if it was (float('inf'), float('-inf))

for line in file1:
    ident, lo, hi = line.split()
    lo = int(lo)
    hi = int(hi)
    old_lo, old_hi = d.get(ident, ((), None))
    d[ident] = (min(lo, old_lo), max(hi, old_hi))

# comparing:
for line in file2:
    ident, val = line.split()
    val = int(val)
    lo, hi = d.get(ident, ((), None))
    if lo <= val <= hi:
        outfile.write(line) # unless you stripped it off, this still has a \n

上記のコードは、私がテストに使用していたものです。file2数秒で100万行を実行します。

于 2013-03-13T17:51:26.810 に答える
0

構築する必要がありますrange(START, END)か?あなたができるとき、それはかなり無駄に思えます:

if START <= x <= END:
    # process

値が範囲内にあるかどうかの確認は、a)リストを作成する必要があり、b)リストを線形検索して見つけるため、時間がかかります。

于 2013-03-13T17:51:41.773 に答える
0

あなたはこのようなことを試すことができます:

In [27]: ranges=defaultdict(list)

In [28]: with open("file1") as f:
    for line in f:
        name,st,end=line.split()
        st,end=int(st),int(end)
        ranges[name].append([st,end])
   ....:         

In [30]: ranges
Out[30]: defaultdict(<type 'list'>, {'A': [[200, 900], [1000, 1200]], 'B': [[100, 700], [900, 1000]]})

In [29]: with open("file2") as f:
    for line in f:
        name,val=line.split()
        val=int(val)
        if any(y[0]<=val<=y[1] for y in ranges[name]):
            print name,val
   ....:             
A 200
A 250
B 100
B 150
于 2013-03-13T17:58:48.183 に答える
0

巧妙なトリック:Pythonを使用すると、オブジェクトとのin比較を行うことができます。これは、を使用するxrangeよりもはるかに高速で、メモリ効率がはるかに高くなります。inrange

だから、あなたはすることができます

from collections import defaultdict

rangedict = defaultdict(list)
...
rangedict[ident].append(xrange(start, end+1))
...

for i in rangedict:
    for r in rangedict[i]:
        if v in r:
            print >>outfile, line
于 2013-03-13T18:08:18.133 に答える