2013-03-22 87 views
0

我正在開發一個涉及基於csv文件的幾個變量/參數創建輸出的項目,並且正在尋找處理它的最佳方法。bash或python csv多字段處理

我有一箇中等規模的CSV文件看起來像:

input.csv

B|Person1|3000 
A|Person2|3000 
C|Person3|5400 
A|Person4|1700 
C|Person5|9400 
D|Person6|2400 
B|Person7|2000 
A|Person8|3400 
A|Person9|1000 
A|Person10|2500 
A|Person11|3000 

想我的輸出看起來像:

output.csv

A|Person2|3000 
A|Person4|1700 
B|Person1|3000 
B|Person7|2000 
C|Person3|5400 
D|Person6|2400 

但輸出只能是6人(AABBCD)和列的總和3 < = 18000。我想的輸出被從 input.csv向下頂行創建的:

  1. 如果行是空的,根據字母AD(Column1),[可選]填寫人員,忽略第3列的總和。
  2. 如果行不是空且列3的總和低於1800 - 跳過(繼續)。
  3. 如果行不是空且列3的總和超過1800,則替換最高值(繼續)。
  4. [可選]完成後,開始檢查過程,看看是否可以替換具有更高值的任何人;根據18000

注本質上創造最高價值的人的名單:所有6個參數必須根據自己的第1列填補。

我剛開始考慮生成一個 output.csv文件,第一列包含AABBCD並使用awk匹配和條件語句添加行。然後我開始研究使用awk數組(將3列傳遞給3個數組並根據索引分配值)...

但是現在,似乎python可能是操縱csv文件時的一種方式,但我在涉及使用python編寫腳本時,我仍然是一名新手。你能否推薦適當的路徑來產生所需的輸出?

非常感謝提前,這一直讓我瘋狂。

編輯:簡單地說 - 只匹配前6位(AABBCD:帶有2As,2Bs,1C,1D),並且具有第3列的末尾總和< = $ 18000。

+1

Python中一路走好!免責聲明:我喜歡Python。現在出於一個更喜歡Python的實際原因:Python代碼可以被編寫爲跨平臺的,雖然你可以在cygwin上使用bash來打算這麼做嗎? – bernie 2013-03-22 22:08:23

+0

輸出是否必須是您指定的那6個? 2和3的意思是什麼,即你的output.csv的值超過1800,即使你說跳過1800以下的值,它的值也低於此值。最後,「替換最高值」表示將當前行添加到最佳? – 2013-03-22 22:50:03

+0

@AndreasGS - 輸出必須是由字母col1字面關聯的組。我想你可能會錯過閱讀,我在找col3的總和等於或小於18,000(不是1800)。 #3只是想解決這個問題,如果#1填補了所有職位並且超過18,000。爲了糾正這個問題,#3將通過替換較大的整數來有選擇地降低整體總和。希望能夠清除它。我讚賞評論。 – LaidBach 2013-03-23 00:36:44

回答

1

這裏有原始的代碼,從中可以很容易適應,以滿足您的需要

import csv 
with open('input.csv') as f_in, open('output.csv', 'w') as f_out : 
    csv_r = csv.reader(f_in, delimiter='|') 
    csv_w = csv.writer(f_out, delimiter='|') 
    col_sum = 0 
    for row in csv_r : 
     if len(row) == 0 : 
      continue 
     elif len(row) == 3 : 
      letter, person, value = row 
      col_sum += int(value) 
      if col_sum < 1800 : 
       csv_w.writerow(row) 
      else : 
       row[2] = 0 
       csv_w.writerow(row) 
+0

這似乎是蟒蛇是我需要使用...我希望我可以讀/寫它更好一點。我會考慮改變這個以滿足我的需求。謝謝! – LaidBach 2013-03-23 01:22:06

+0

如果我沒有弄錯,這將處理檢查col_sum並將總數保持在18k以下的所有事情。但是,我怎麼能限制這個代碼只生成2As,2Bs,1C,1D的6個插槽?目前正在查看更多csv ...謝謝! – LaidBach 2013-03-24 00:49:13

0

如果我理解正確的一切......這裏去。

import csv 

def get_subset(rows): 
    sub_sets = [] 
    #get all combinations of rows 
    for L in range(0, len(rows)+1): 
     for subset in itertools.combinations(rows, L): 
      sub_sets.append(subset) 

    #get all combinations less than six 
    lessthansix = filter(lambda x: True if len(x) <= 6 else False, sub_sets) 
    #get all combinations less than or equal to max 
    lessthanmax = filter(lambda x: True if sum([int(col[2]) for col in x]) <= 18000 else False, lessthansix) 
    #sort the less than max groups by sum of col 3 
    closesttomax = sorted(lessthanmax, reverse=True, key=lambda x: sum([int(col[2]) for col in x])) 

    return closesttomax[0] 

with open("test.csv", 'r') as f: 
    reader = csv.reader(f, delimiter="|") 
    #filter out all rows that have col 3 less than 1800 
    rows = [row for row in reader if int(row[2]) > 1800] 
    subset = get_subset(rows) 
    sorted_rows = sorted(subset, key=lambda x: x[0]) 
    with open("out.csv", 'w') as o: 
     writer = csv.writer(o) 
     print sorted_rows 
     print sum([int(col[2]) for col in sorted_rows]) 
     for row in sorted_rows: 
      writer.writerow(row) 
+0

這是接近我所需要的。與此相關的問題是,它提供了18000以下的最佳組合。我需要它填寫所有6個AABBDC行。我不是Python大師,所以我可能錯過了一些東西,但我的輸出是:[['B','Person1','3000'],['C','Person3','5400'],['C '''Person5','9400']] 17800.我更感興趣的是使用18000以下所有景點中索引最高的人物。謝謝,我會仔細研究一下,看看我是否可以調整它。 – LaidBach 2013-03-23 01:13:59

+0

@LaidBach在你提供的數據集中沒有6的組合,不超過18000. – John 2013-03-23 11:52:58

+0

嗯,我的樣本輸出使用數據集加起來不到18000。我將繼續測試您提供的大數據集的代碼。我正在更多地使用python查看CSV和itertools。再次感謝您的幫助。此外,我看到過濾器中的錯字爲1800而不是18000 - 讓我看看有什麼調整。謝謝!更新:將值更改爲18000,並將行參數更改爲<= 18000(而不是> 18000)。現在我唯一擔心的是如果它將一個更大的數據集排序爲只有2As,2Bs,1C,1D。 (測試..)謝謝! – LaidBach 2013-03-24 00:29:45

1

這裏也是一個awk的版本,你可以嘗試:

awk -F\| ' 
    NR<=set{ 
    A[NR]=$0 
    total+=$NF 
    values[NR]=$3 
    next 
    } 

    total>treshold{ 
    max=0 
    for(i in values) if (values[i]>max){ 
     max=values[i]; j=i 
    } 
    if (max > $NF) { 
     A[j]=$0 
     total+=$NF-max 
     values[j]=$NF 
    } 
    } 

    END{ 
    print total; for(i in A) print A[i] 
    } 
' set=6 treshold=18000 file | sort 
+0

謝謝! (免責聲明:仍在學習)我沒有看到將輸出限制在2As,2Bs,1C和1D中的6個的情況。除非A [NR] = $ 0這麼做。再次感謝。 – LaidBach 2013-03-24 00:42:00