0

필자는 파일에서 어떤 정보를 가져 오거나 여러 단계를 거쳐 최종 원하는 형식으로 데이터를 마사지해야하는 상황에 계속해서 직면합니다. 예를 들면 :불필요한 목록을 만드는 것을 피하는 방법은 무엇입니까?

에 나오는 위의 예
def insight_pull(file): 
    with open(file) as in_f: 
     lines = in_f.readlines() 

     dirty = [line.split(' ') for line in lines] 
     clean = [i[1] for i in dirty] 
     cleaner = [[clean[i],clean[i + 1]] for i in range(0, len(clean),2)] 
     cleanest = [i[0].split() + i[1].split() for i in cleaner] 


     with open("Output_File.txt", "w") as out_f: 
      out_f.writelines(' '.join(i) + '\n' for i in cleanest) 

:

# Pull raw data from file splitting on ' '. 
    dirty = [line.split(' ') for line in lines] 

    # Select every 2nd element from each nested list. 
    clean = [i[1] for i in dirty] 

    # Couple every 2nd element with it's predecessor into a new list. 
    cleaner = [[clean[i],clean[i + 1]] for i in range(0, len(clean),2)] 

    # Split each entry in cleaner into the final formatted list. 
    cleanest = [i[0].split() + i[1].split() for i in cleaner] 

(각 편집이 전에 편집에 의존하기 때문에) 내가 한 줄 또는 루프로 모든 편집을 넣을 수 없습니다로보고 이런 식으로 코드를 구조화하는 더 좋은 방법이 있을까요?

질문이 다소 모호한 경우 사과드립니다. 모든 입력을 많이 주시면 감사하겠습니다.

+1

을 기술적으로, 당신은 잘못이 지능형리스트를 할 수 있기 때문에 당신이 모두 한 줄에서이 작업을 수행하지 못할 것을 말하는 다른 목록을 작성하면 출력되지만, 그렇게하면 안됩니다. –

+1

일부 샘플 입력 및 출력을 표시 할 수 있습니까? – pault

+0

불행히도 일부 데이터는 민감하지 않지만 위의 예는 요점을 설명하기위한 것입니다. 이런 종류의 문제가 계속 발생하고 있습니다. – blackmore5

답변

2

생성기는

가 여러 목록을 만들 싶지 않다에서 올바른 식입니다. 귀하의 목록 이해력은 전체 목록을 작성하고, 메모리를 낭비하며, 각 목록을 반복합니다!

@ 생성자를 재사용하기 위해 코드에 다른 위치가있는 경우 gerrators를 사용하는 VPfB의 아이디어가 좋은 해결책입니다. 당신이 발전기를 재사용 할 필요가 없다면 발전기 표현식을 사용하십시오.

생성자 표현식은 생성자와 같이 지연이 있으므로 함께 연결될 때 여기에서 루프는 최종적으로 쓰기 라인이 호출 될 때 한 번 평가됩니다.그것은 직접 질문을 일치로

def insight_pull(file): 
    with open(file) as in_f: 
     dirty = (line.split(' ') for line in in_f) # Combine with next 
     clean = (i[1] for i in dirty) 
     cleaner = (pair for pair in zip(clean,clean)) # Redundantly silly 
     cleanest = (i[0].split() + i[1].split() for i in cleaner) 

     # Don't build a single (possibily huge) string with join 
     with open("Output_File.txt", "w") as out_f: 
      out_f.writelines(' '.join(i) + '\n' for i in cleanest) 

위를 떠나, 당신은 더 이상 갈 수

def insight_pull(file): 
    with open(file) as in_f: 
     clean = (line.split(' ')[0] for line in in_f) 
     cleaner = zip(clean,clean) 
     cleanest = (i[0].split() + i[1].split() for i in cleaner) 

     with open("Output_File.txt", "w") as out_f: 
      for line in cleanest: 
       out_f.write(line + '\n') 
+0

좋은 답변을 많이했지만 머리에 못을 박은 것 같아요. 나는 발전기 표현에 대한 나의 이해를 털어 놓아야했다. 감사! – blackmore5

1

귀하의 예에서 cleanest 목록 만 실용적인 가치가 있다고 가정하고 나머지는 중간 단계이며 걱정없이 폐기 될 수 있습니다.

그렇다고 가정하면, 동일한 변수를 각 중간 단계에 재사용하지 않고 메모리에 여러 목록을 보유하지 않는 이유는 무엇입니까?

def insight_pull(file): 
    with open(file) as in_f: 
     my_list = in_f.readlines() 

     my_list = [line.split(' ') for line in my_list] 
     my_list = [i[1] for i in my_list] 
     my_list = [[my_list[i],my_list[i + 1]] for i in range(0, len(my_list),2)] 
     my_list = [i[0].split() + i[1].split() for i in my_list] 


    with open("Output_File.txt", "w") as out_f: 
     out_f.writelines(' '.join(i) + '\n' for i in my_list) 
+0

이렇게하면 x5 메모리를 절약 할 수 있지만 각 목록 이해는 전체 새 목록을 할당하고 작성하는 것입니다. – digitalsentinel

1

성능 측면에서 생각해 보면 발전기를 찾고 있습니다. 생성기는 목록과 매우 비슷하지만 느리게 평가됩니다. 즉, 각 요소는 필요한 경우에만 생성됩니다. 예를 들어, 다음과 같은 순서로, 실제로 전체 목록을 3 개 만들지는 않습니다. 각 요소는 한 번만 평가됩니다. (난 당신의 코드는 당신이로 실행하는 문제의 예, 그리고 구체적인 문제라고 이해되는) 아래는 발전기의 단지 예를 들어, 사용하는 것입니다 :

# All even values from 2-18 
even = (i*2 for i in range(1, 10)) 

# Only those divisible by 3 
multiples_of_3 = (val for val in even if val % 3 == 0) 

# And finally, we want to evaluate the remaining values as hex 
hexes = [hex(val) for val in multiples_of_3] 
# output: ['0x6', '0xc', '0x12'] 

처음 두 표현은 발전기, 그리고 마지막으로 단지 목록을 이해하는 것입니다. 중간 단계 목록을 만들지 않기 때문에 많은 단계가있을 때 많은 메모리를 절약 할 수 있습니다. 생성자는 인덱싱 할 수 없으며 한 번만 평가할 수 있습니다 (값의 스트림 일뿐입니다).

1

목표를 달성하려면 파이프 라인 처리를 권장합니다. 나는 기술을 누설하는 기사를 발견했다 : generator pipelines.

루프를 파이프 라인으로 직접 변환하려고했습니다. 코드는 테스트되지 않았으므로 (테스트 할 데이터가 없기 때문에) 버그가있을 수 있습니다.

func 이름의 앞부분 인 f은 필터를 나타냅니다.

def fromfile(name): 
    # see coments 
    with open(name) as in_f: 
     for line in in_f: 
      yield line 

def fsplit(pp): 
    for line in pp: 
     yield line.split(' ') 

def fitem1(pp): 
    for item in pp: 
     yield item[1] 

def fpairs(pp): 
    # edited 
    for x in pp: 
     try: 
      yield [x, next(pp)] 
     except StopIteration: 
      break 

def fcleanup(pp): 
    for i in pp: 
     yield i[0].split() + i[1].split() 

pipeline = fcleanup(fpairs(fitem1(fsplit(fromfile(NAME))))) 

output = list(pipeline) 

실제 사용을 위해 나는 처음 3 개의 필터와 다음 2 개의 필터를 집계합니다.

+0

이러한 기능을 재사용 할 수 있다면 좋은 아이디어입니다 ... 1) 파일 생성기를 생성합니다. 이미 하나입니다. 2) fpairs()는 처리되지 않은 StopIteration을 발생시킬 수 있습니다. – digitalsentinel

+0

@digitalsentinel 파일이 이미 생성기에 관한 좋은 지적. 나는 그대로 코드를 남기기로했다. StopIteration에 관해서는,'fpairs'가 모두 소모되었다는 신호를 보냅니다. 맞습니다. '[(1,2,3,4,5))))')''[[1, 2], [3, 4]]'를 출력한다. – VPfB

+0

@digitalsentin I StopIteration과 관련하여 잘못되었습니다. 이제는 PEP479에 의해 부정확 한 것으로 간주됩니다. – VPfB