根据值

时间:2015-09-28 22:45:01

标签: bash unix

我有一个制表符分隔文件,如下所示:

cat my file.txt

给出:

    1   299
    1   150
    1   50
    1   57
    2   -45
    2   62
    3   515
    3   215
    3   -315
    3   -35
    3   3
    3   6789
    3   34
    5   66
    5   1334
    5   123

我想使用Unix命令获取基于制造商分隔的文件,该文件基于第1列中的值,输出文件的每一列都将包含第2列的所有相关值 (我在这里使用的是分隔符“|”而不是tab,仅用于说明我想要的输出文件):

299   |   -45   |   515   |   66
150   |   62    |   215   |   1334
50    |         |   -315  |
57    |         |   -35   |
      |         |    3    |

相应的Headers(1,2,3,5;基于第1列值)可能是代码的一个很好的补充(如下所示),但主要的要求是将第一个文件的信息拆分成分隔列。谢谢!

1     |    2    |   3     |   5       
299   |   -45   |   515   |   66
150   |   62    |   215   |   1334
50    |         |   -315  |
57    |         |   -35   |
      |         |    3    |

4 个答案:

答案 0 :(得分:2)

这是一个与您的输出相匹配的衬垫。它构建一个字符串$ARGS,其中包含与第一列中的唯一值一样多的进程替换。然后,$ARGS用作paste命令的参数:

HEADERS=$(cut -f 1 file.txt | sort -n | uniq); ARGS=""; for h in $HEADERS; do ARGS+=" <(grep ^"$h"$'\t' file.txt | cut -f 2)"; done; echo $HEADERS | tr ' ' '|'; eval "paste -d '|' $ARGS"

输出:

1|2|3|5
299|-45|515|66
150|62|215|1334
50||-315|
57||-35|
||3|

答案 1 :(得分:1)

您可以使用gnu-awk

awk '
BEGIN{max=0;}
{
    d[$1][length(d[$1])+1] = $2;
    if(length(d[$1])>max) 
        max = length(d[$1]);
}
END{
    PROCINFO["sorted_in"] = "@ind_num_asc";
    line = "";
    flag = 0;
    for(j in d){
        line = line (flag?"\t|\t":"") j;
        flag = 1;
    }
    print line;
    for(i=1; i<=max; ++i){ 
        line = "";
        flag = 0;
        for(j in d){
            line = line (flag?"\t|\t":"") d[j][i];
            flag = 1;
        } 
        print line;
    }
}' file.txt

你得到了

1   |   2   |   3   |   5
299 |   -45 |   515 |   66
150 |   62  |   215 |   1334
50  |       |   -315    |   
57  |       |   -35 |   
    |       |   3   |   

或者,您可以使用python ....例如split2Columns.py

import sys
records = [line.split() for line in open(sys.argv[1])]
import collections
records_dict = collections.defaultdict(list)
for key, val in records:
    records_dict[key].append(val)

from itertools import izip_longest
print "\t|\t".join(records_dict.keys())
print "\n".join(("\t|\t".join(map(str,l)) for l in izip_longest(*records_dict.values(), fillvalue="")))
python split2Columns.py file.txt

你得到相同的结果

答案 2 :(得分:1)

@Jose Ricardo Bustos M. - 谢谢你的回答!我很遗憾无法在我的Mac上安装gnu-awk,但基于你的暗示性答案,我使用awk执行了类似的操作:

private final static String SELECTED_ITEM = "MyAdapter.mSelectedItem";

//Save your selection
@Override
public void onSaveInstanceState(Bundle outState) {
    if(null!=mAdapter){
        outState.putInt(SELECTED_ITEM, mAdapter.mSelectedItem);
    }
    super.onSaveInstanceState(outState);
}

//Restore your selection
@Override
public void onActivityCreated(Bundle savedInstanceState){
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        mAdapter.notifyItemChanged(platformsAdapter.mSelectedItem);
        mAdapter.mSelectedItem = savedInstanceState.getInt(SELECTED_ITEM, 0);
        mAdapter.notifyItemChanged(platformsAdapter.mSelectedItem);
        mRecyclerView.post(new Runnable() {
            @Override
            public void run() {
                //Align selection to top
                mLayoutManager
                    .scrollToPositionWithOffset(mAdapter.mSelectedItem, 0);
            }
        });
    }
}

答案 3 :(得分:0)

这是使用数组来跟踪列标题,使用它们来命名临时文件和paste最终所有内容:

#!/bin/bash

infile=$1
filenames=()
idx=0

while read -r key value; do
   if [[ "${filenames[$idx]}" != "$key" ]]; then
       (( ++idx ))
       filenames[$idx]="$key"
       echo -e "$key\n----" > "$key"
   fi
   echo "$value" >> "$key"
done < "$1"

paste "${filenames[@]}"

rm "${filenames[@]}"