複数のファイルがあり、それぞれに 2 つの列があります。
例えば :
ファイル1.txt
ID Value1
1 40
2 30
3 70
ファイル2.txt
ID Value2
3 50
4 70
9 20
等々、
ファイル1230.txt
ID Value150
9 98
10 52
2 71
最初の列に基づいて(ファイル間の交差に基づいて)これらのファイルを結合するにはどうすればよいですか?出力は次のようになります。
ID Value1 Value2 Value150
1 40 0 0
2 30 0 71
3 70 50 0
4 0 70 0
9 0 20 98
10 0 0 52
awk または Linux コマンドを使用してこれを支援できる人はいますか。
ありがとう。
答え1
Python を使用してこれを行う 1 つの方法を次に示します。
コード:
import sys
columns = []
data = {}
ids = set()
for filename in sys.argv[1:]:
with open(filename, 'rU') as f:
key = next(f).strip().split()[1]
columns.append(key)
data[key] = {}
for line in f:
if line.strip():
id, value = line.strip().split()
try:
data[key][int(id)] = value
except ValueError as exc:
raise ValueError(
"Problem in line: '{}' '{}' '{}'".format(
id, value, line.rstrip()))
ids.add(int(id))
print('\t'.join(['ID'] + columns))
for id in sorted(ids):
line = []
for column in columns:
line.append(data[column].get(id, '0'))
print('\t'.join([str(id)] + line))
結果:
ID Value1 Value2 Value150
1 40 0 0
2 30 0 71
3 70 50 0
4 0 70 0
9 0 20 98
10 0 0 52
答え2
コマンドライン ツールを使用した Bash ソリューション。入力ファイル リストの順序が正しくなかったため、ls -v
に出力されましたcat
。
while read line; do
if [[ "$line" =~ ID ]]; then
array=${line##* }
index+=($array)
continue
else
eval $array'[${line% *}]=${line#* }'
fi
done <<<"$( cat $(ls -v file[0-9]*.txt) )"
printf ID
for name in ${index[@]}; do
printf ' %s' $name
done
echo
max_ind=$( sort -nu file[0-9]*.txt | tail -n1 | cut -d' ' -f1 )
for (( j = 1 ; j <= $max_ind ; j++ )); do
for (( i = 0 ; i < ${#index[@]} ; i++ )); do
value=$( eval 'echo ${'${index[i]}'[j]}' )
roll+=$( [ "$value" ] &&
printf "%-${#index[i]}s " $value ||
printf "%-${#index[i]}s " 0 )
done
[[ "$roll" =~ [^0\ ] ]] && printf '%-4s%s\n' $j "$roll"
unset roll
done