我昨天问了这个问题并且得不到合适的答案,但其中很多都没有具体说明。
我有一个有趣的问题,我不太确定如何最好地解决,迭代列表。使用以下格式 -
element, date, unixTime, before, after
CZ, 12/27/07 3:55 PM, 1198788900, 42345, 42346
CZ, 12/27/07 5:30 PM, 1198794600, 42346, 42300
CZ, 12/27/07 7:05 PM,1198800300, 42300, 42000
JB, 12/27/07 7:05 PM,1198800300, 13722, 13500
I, 12/27/2007 7:05 PM, 1198800300, 4475, 4572
我想迭代,为每个唯一元素和每个日期迭代,并获得前/后列中更改的符号。例如,对于CZ JB和I,我想要3行12/27/2007。有数百万行,有时每天有数千行,我只需要打印当天每个元素的最后一行。所以12/27的“CZ”线有多个,可能是数百或数千个。我只需要拉出最后一个,并打印输出“CZ,12/27 / 07,1”或“CZ,12/27/07,-1”。对于12/27,CZ的最后一行是负方向,因此它打印-1。它对JB,我和所有其他元素也会这样做。该文件按unix时间排序,元素可以混淆。我希望输出看起来像下面的
element, date, direction
CZ, 12/27/07, -1
JB, 12/27/07, -1
I, 12/27/07, 1
CZ, 12/28/07, 1
JB, 12/27/07, -1
I, 12/27/07, -1
试图在bash,python,perl中找到一种简洁的方法,甚至像awk这样的东西来做这样的事情。对于每一天,它将为当天至少有一行的每个元素指明方向。我考虑过这样做的慢速方法,比如阅读文件,填充“元素”和“日期”表,然后做一个foreach并比较每个集合以找到最大的unix时间然后用它打印,但是必须有一个相反,更好的方式来完成它。
答案 0 :(得分:0)
这似乎是dict
dict
的申请。
由于您可以指望使用最新的值覆盖该值,因此在unixtime中,您可以动态构建dict
,按日期键入,然后在其中为每个元素添加dict
。
import csv
d = {}
with open('inputfile.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
element = row[0]
date = row[1]
before = float(row[3])
after = float(row[4])
if date not in d:
d[date] = {}
if before < after:
d[date][element] = 1
else:
d[date][element] = -1
如果您需要输出必须按日期排序,您可以获取日期并对其进行排序。
from datetime import datetime
dates = [datetime.strptime(date.split(None)[0], '%y/%m/%d')
for date d.keys()]
sorted(dates)
否则你可以按原样抓取日期。
dates = d.keys()
然后只需编写输出文件
with open('outfile.csv', 'wb') as f:
writer = csv.writer(f)
writer.writerow(['element', 'date', 'direction'])
for date in dates:
for element in d[date]:
writer.writerow([delement, date, d[date][element]])
答案 1 :(得分:0)
您也可以考虑使用groupby
如果您的数据已采用以下格式:
[
['CZ', '12/27/07 3:55 PM', '1198788900', '42345', '42346',],
['CZ', '12/27/07 5:30 PM', '1198794600', '42346', '42300',],
['CZ', '12/27/07 7:05 PM','1198800300', '42300', '42000',],
['JB', '12/27/07 7:05 PM','1198800300', '13722', '13500',],
['I', '12/27/07 7:05 PM', '1198800300', '4475', '4572']
]
然后你可以这样做:
#truncate out the time portion of the second col:
for row in data:
row[1] = row[1].split(" ")[0]
#sort by symbol and date
data = sorted(data, key = lambda x: (x[0], int(x[2])))
from itertools import groupby
for k, g in groupby(data, lambda x:x[:2]):
before,after = list(g)[-1][-2:] #extracts the last line.
k.append( "1" if int(after) > int(before) else "-1" )
print ",".join(k)
使用以下输出:
CZ,12/27/07,-1
I,12/27/07,1
JB,12/27/07,-1
答案 2 :(得分:0)
Perl(已测试):
use warnings;
use strict;
my ($inputfile, %output) = "input.csv";
open (my $pfile, '<', "$inputfile") or die "Couldn't open file '$inputfile'\n";
<$pfile>; # SKIPS HEADER LINE, delete if there is no header present
while (my $row = <$pfile>) {
die "Malformed line: $row" if $row !~ /^\s*(\S+)\s*,\s*(\d\d\/\d\d\/)(\d\d)(\d\d)?\s[^,]*,[^,]*,\s*(\d+)\s*,\s*(\d+)\s*$/;
my ($element, $date, $before, $after) = ($1, $2.($4 ? $4 : $3), $5, $6);
$output{$element . $date} = [ $element, $date, $before - $after < 0 ? -1 : 1 ];
}
close $pfile;
print join(',', @$_)."\n" foreach ([ "element", "date", "direction" ], values %output);
答案 3 :(得分:0)
在GNU awk中(正则表达式FS
)。它只缓冲先前(和当前)记录,因此它需要排序的输入文件,并且一旦大小无关紧要:
$ awk -F"(, |,| )" -v OFS="," '
p!=($1 OFS $2) && NR>1 { # when $1 and $2 change
print p, q # print previous
}
{
p=$1 OFS $2 # set previous
q=$7-$6
q=( q ? q/sqrt(q^2) : ( NR==1 ? "direction" : 0 ) ) # determine -1,0,1
}
END {
print p, q # last line handling
}
' file
element,date,direction
CZ,12/27/07,-1
JB,12/27/07,-1
I,12/27/2007,1