2014-01-27 3 views
2

Представьте, что я читаю в CSV-файл чисел, который выглядит следующим образом:карта функция столбцов списка итератора

1,6.2,10 
5.4,5,11 
17,1.5,5 
... 

И это действительно очень долго.

Я собираюсь перебирать этот файл с читателем CSV, как это:

import csv 
reader = csv.reader('numbers.csv') 

Теперь предположим у меня есть некоторые функции, которые могут принимать итератор как максимум:

max((float(rec[0]) for rec in reader)) 

Это находит максимум первого столбца и не нужно считывать весь файл в память.

Но что, если я хочу запустить max на каждый столбец csv-файла, все еще не читая весь файл в память?

Если Макс были переписаны так:

def max(iterator): 
    themax = float('-inf') 
    for i in iterator: 
     themax = i if i > themax else themax 
     yield 
    yield themax 

я мог бы сделать некоторые фантазии работы (и есть), чтобы это произошло.

Но что, если я сдерживаю проблему и не позволяю переписывать max? Это возможно?

Спасибо!

ответ

1

Я бы просто отойти от использования функции, которые вы передаете итератор, но вместо того, чтобы перебирать самостоятельно над читателем:

maxes = [] 
for row in reader: 
    for i in range(len(row)): 
     if i > len(maxes): 
      maxes.append(row[i]) 
     else: 
      maxes[i] = max(maxes[i], row[i]) 

В конце, вы будете иметь список maxes, который будет содержать каждый максимум значение, не имея всего файла в памяти.

2

Если вам удобно работать с более функциональным подходом, вы можете использовать functools.reduce для итерации по файлу, одновременно вытаскивая сразу две строки в память и накапливая максимальные значения столбцов по мере их поступления.

import csv 
from functools import reduce 

def column_max(row1, row2): 
    # zip contiguous rows and apply max to each of the column pairs 
    return [max(float(c1), float(c2)) for (c1, c2) in zip(row1, row2)] 

reader = csv.reader('numbers.csv') 
# calling `next` on reader advances its state by one row 
first_row = next(reader) 
column_maxes = reduce(column_max, reader, first_row) 
# 
# 
# another way to write this code is to unpack the reduction into explicit iteration 
column_maxes = next(reader) # advances `reader` to its second row 
for row in reader: 
    column_maxes = [max(float(c1), float(c2)) for (c1, c2) in zip(column_maxes, row)] 
0
def col_max(x0,x1): 
    """x0 is a list of the accumulated maxes so far, 
    x1 is a line from the file.""" 
    return [max(a,b) for a,b in zip(x0,x1)] 

Теперь functools.reduce (col_max, читатель, инициализатор) будет возвращать только то, что вы хотите. Вам нужно будет предоставить инициализатор в виде списка -inf с правильной длиной.

Смежные вопросы