这显然是一个流行的面试问题:
有 2 个包含恐龙数据的 CSV 文件。我们需要查询它们以返回满足特定条件的恐龙。
有 2 个选择 - 仅使用 Unix 命令行工具 ( /// cut
) ,或者使用 Python 等脚本语言,但是paste
sed
awk
没有额外的模块像q
, fsql
,csvkit
等等
- 文件1.csv:
NAME,LEG_LENGTH,DIET Hadrosaurus,1.2,herbivore Struthiomimus,0.92,omnivore Velociraptor,1.0,carnivore Triceratops,0.87,herbivore Euoplocephalus,1.6,herbivore Stegosaurus,1.40,herbivore Tyrannosaurus Rex,2.5,carnivore
- 文件2.csv
NAME,STRIDE_LENGTH,STANCE Euoplocephalus,1.87,quadrupedal Stegosaurus,1.90,quadrupedal Tyrannosaurus Rex,5.76,bipedal Hadrosaurus,1.4,bipedal Deinonychus,1.21,bipedal Struthiomimus,1.34,bipedal Velociraptor,2.72,bipedal
- 使用论坛:
在哪里speed = ((STRIDE_LENGTH / LEG_LENGTH) - 1) * SQRT(LEG_LENGTH * g)
g = 9.8 m/s^2
编写一个程序来读取 csv 文件,并仅打印双足恐龙的名称,按速度从最快到最慢排序。
在 SQL 中,这很简单:
select f2.name from
file1 f1 join file2 f2 on f1.name = f2.name
where f1.stance = 'bipedal'
order by (f2.stride_length/f1.leg_length - 1)*pow(f1.leg_length*9.8,0.5) desc
如何在 Bash 或 Python 中完成此操作?
答案1
已经创建了一些工具来实现此目的。这是示例:
$ csvq 'select * from cities'
+------------+-------------+----------+
| name | population | country |
+------------+-------------+----------+
| warsaw | 1700000 | poland |
| ciechanowo | 46000 | poland |
| berlin | 3500000 | germany |
+------------+-------------+----------+
$ csvq 'insert into cities values("dallas", 1, "america")'
1 record inserted on "C:\\cities.csv".
Commit: file "C:\\cities.csv" is updated.
答案2
你提到这是一个面试问题。如果我在面试中被问到这个问题,我会问有关这些限制的问题,例如,为什么我们有这些限制,什么是允许的,什么是不允许的,原因是什么。对于每个问题,我都会尝试将其与为什么我们在业务环境中存在局限性联系起来,以真正理解这里发生的事情。
另外,我想问一下动物速度公式的起源,但这只是因为我的物理科学背景比我的生命科学背景强,我对此很好奇。
作为一名面试官,我真的很想听到有用于 CSV 解析的标准工具。我会特别留意听到使用脚本或命令行实用程序从头开始解析/修改不如使用pandas
和等标准工具可取csv
。
Stack Exchange 不适合这种类型的迭代问答,因此我将仅使用 Python 发布一个答案,只有在真正了解业务问题后,我才会在面试中提供该答案。
# Assume it's OK to import sqrt, otherwise the spirit of the problem isn't understood.
from math import sqrt
# Read data into dictionary.
dino_dict = dict()
for filename in ['file1.csv','file2.csv']:
with open(filename) as f:
# Read the first line as the CSV headers/labels.
labels = f.readline().strip().split(',')
# Read the data lines.
for line in f.readlines():
values = line.strip().split(',')
# For each line insert the data in the dict.
for label, value in zip(labels, values):
if label == "NAME":
dino_name = value
if dino_name not in dino_dict:
dino_dict[dino_name] = dict() # New dino.
else:
dino_dict[dino_name][label] = value # New attribute.
# Calculate speed and insert into dictionary.
for dino_stats in dino_dict.values():
try:
stride_length = float(dino_stats['STRIDE_LENGTH'])
leg_length = float(dino_stats['LEG_LENGTH'])
except KeyError:
continue
dino_stats["SPEED"] = ((stride_length / leg_length) - 1) * sqrt(leg_length * 9.8)
# Make a list of dinos with their speeds.
bipedal_dinos_with_speed = list()
for dino_name, dino_stats in dino_dict.items():
if dino_stats.get('STANCE') == 'bipedal':
if 'SPEED' in dino_stats:
bipedal_dinos_with_speed.append((dino_name, dino_stats['SPEED']))
# Sort the list by speed and print the dino names.
[dino_name for dino_name, _ in sorted(bipedal_dinos_with_speed, key=lambda x: x[1], reverse=True)]
[‘霸王龙’、‘迅猛龙’、‘拟鸵鸟’、‘鸭嘴龙’]
答案3
你可以使用伟大的磨坊主并运行
mlr --csv join -j NAME -f file1.csv \
then put '$speed=($STRIDE_LENGTH/LEG_LENGTH - 1)*pow(($LEG_LENGTH*9.8),0.5)' \
then sort -nr speed \
then cut -f NAME file2.csv
获得
NAME
Tyrannosaurus Rex
Velociraptor
Euoplocephalus
Stegosaurus
Hadrosaurus
Struthiomimus
您可以通过 bash(和其他脚本语言)在几乎所有操作系统和脚本中使用它。就像剪切/粘贴/sed/awk 一样。
答案4
A gawk
但在内部进行初始排序join
和最终排序awk
join -t, <(sort file1.csv) <(sort file2.csv) |
awk -F, -v g=9.8 '/bipedal/{osaur[$1]=($4/$2-1)*sqrt(g*$2)}
END{PROCINFO["sorted_in"]="@val_num_desc"; for (d in osaur) print d}'
Tyrannosaurus Rex
Velociraptor
Struthiomimus
Hadrosaurus
编辑@Cbhihe 评论
关于控制方式的有用资源gawk
扫描数组。
PROCINFO["sorted_in"]
可以设置来控制读取数组的顺序。
在这种情况下,使用@val
ue 并假设它们是num
eric 并将它们排序desc
为结尾,因此@val_num_desc
。
一个数组同样可以使用ices输出,@ind
假设它们是str
ings并对它们进行排序asc
,在这种情况下它会是@ind_str_asc
这些苍蝇的任何组合以及所有这些都在链接的资源中。