1

我有一个大的排序文件,每行一个数字。我想输出某个大小的每个范围内的数字数量。因此,例如将范围设为 10 并将输入设为

1
4
34
37
42
48
53

输出应该是[2, 1, 3, 2, 2, 2, 1]. 这是 的长度[1,4], [4], [34,37,42], [37,42], [42,48], [48,53], [53]。我认为这可以通过使用来解决,deque但是,主要是作为编程练习并使用更少的内存,我试图通过打开文件两次并在文件中有两个不同的指针来解决。一个在列表的下一个左端读取,一个在新的右手端读取。所以我的代码有

fin1 = open(file, 'r')
fin2 = open(file, 'r')

我认为在 fin1 上循环,当范围变得太大时,我会读入更多的 fin2,直到范围足够小,然后继续降低 fin1 和 fin2。

但是我无法让它工作。似乎不喜欢我为同一个文件打开两个文件句柄。怎么能做到这一点?

4

4 回答 4

3

这是一个itertools.tee()用于模拟从句柄读取的解决方案,但实际上只打开一个:

from itertools import tee

def sliding_range(file, size):
    fin1, fin2 = tee(int(ln.strip()) for ln in open(file) if ln.strip())
    n = 1
    next(fin2)
    val2 = next(fin2)
    for val1 in fin1:
        while val2 is not None and val2 <= val1 + size:
            n += 1
            try:
                val2 = next(fin2)
            except StopIteration:
                val2 = None
                break
        yield n
        n -= 1

示例(将示例数据复制到“test.txt”):

>>> list(sliding_range('test.txt', 10))
[2, 1, 3, 2, 2, 2, 1]
于 2013-07-31T18:38:37.683 回答
1

这是一个实现,可能有更好的方法来做到这一点,但这应该可行。我假设您在问题中发布的相同输入。

def ranges(n):
    f = open("tmp.txt")

    while True:
        i = f.tell()
        try:
            curr = int(f.readline().rstrip())
        except ValueError:
            break  # EOF

        j = f.tell()

        while True:
            k = f.tell()  # End of range location
            try:
                next = int(f.readline().rstrip())
            except ValueError:
                break  # EOF

            if next < n or (next - curr) < n:
                continue
            else:
                break

        f.seek(i)  # Go to beginning of range

        r = []
        while f.tell() < k:
            r.append(int(f.readline().strip()))
        print(r)

        f.seek(j)  # Go to line after beginning of range


>>> ranges(10)
[1, 4]
[4]
[34, 37, 42]
[42, 48]
[48, 53]
[53]
于 2013-07-31T18:30:46.790 回答
1

编辑:我以前的实现是双端队列解决方案(而不是完美的解决方案)。这是带有 2 个文件指针的解决方案:

def sliding_ranges(filename=r"C:\Temp\data.txt", N=10):
    f1, f2 = open(filename), open(filename)
    k, res, i1, i2, r1, r2 = 1, [], 0, 0, 1, 1
    while True:
        while r2 and (not i2 or i2 - i1 < N):
            r2, k = f2.readline(), k + 1
            if r2: i2 = int(r2)

        while r1 and (not i1 or not r2 or i2 - i1 > N):
            r1, k = f1.readline(), k - 1
            if i1: res.append(k)
            if r1: i1 = int(r1)

        if not r1: break

    return res

    >>> sliding_ranges(r"C:\Temp\data.txt", 10)
    [2, 1, 3, 2, 2, 2, 1]

上一个:这是一次通过的实现。当你遍历时,你一直在计算列表的长度

f = open(r"d:\temp\data.txt")

d, res, N = [], {}, 10
for j in f:
    i = int(j)
    if i not in res: res[i] = 1
    for k, v in res.items():
        if i - k > N:
            d.append(v)
            del res[k]
        elif k != i:
            res[k] += 1 
d = d + [v for v in res.values()]

这是每次迭代中的对象列表

d []
res {}

d []
res {1: 1}

d []
res {1: 2, 4: 1}

d [2, 1]
res {34: 1}

d [2, 1]
res {34: 2, 37: 1}

d [2, 1]
res {34: 3, 42: 1, 37: 2}

d [2, 1, 3, 2]
res {42: 2, 48: 1}

d = [2, 1, 3, 2, 2, 2, 1]
于 2013-07-31T18:35:06.260 回答
0

我不确定您为什么要这样做,但要回答您的问题(这是关于文件 I/O 而不是计数值),您需要一个文件句柄和两个文件指针。

使用文件句柄打开文件后ff.tell()将告诉您您在文件中的位置,并将f.seek(pos)指针移回给定位置。

f.seek(pos,how)接受一个可选的第二个参数,它使您在如何计算搜索方面具有一定的灵活性(how从文件开头设置为 0,从当前位置设置为 1,从结尾设置为 2)。这使您可以将pos其用作参考的偏移量,而不是严格从头开始。

于 2013-07-31T18:23:47.360 回答