计算滑动范围内的点数

时间:2013-07-31 18:09:18

标签: python

我有一个大的排序文件,每行一个数字。我想输出一些大小的每个范围内的数字。例如,将范围设为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 个答案:

答案 0 :(得分: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]

答案 1 :(得分: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]

答案 2 :(得分:1)

编辑:我之前的实施是deque解决方案(并非完美解决方案)。这是带有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]

PREVIOUS:这是一次通过的实现。当你正在遍历时,你会继续计算列表的长度

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]

答案 3 :(得分:0)

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

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

f.seek(pos,how)采用可选的第二个参数,为您提供搜索搜索方式的灵活性(将how设置为0从文件的开头搜索,1从当前位置设置,2从结束)。这允许您使用pos作为参考的偏移量,而不是严格地从头开始。