2017-02-18 6 views
1

у меня есть линия, которая идет как:рода строка с кучей цифр

string 2 2 3 3 1 4 

, где вторая, четвёртая и 6-й столбцы представляют идентификатор (предполагая, что каждый идентификационный номер является уникальным) и 3-й, 5-й и 7-й столбцы представляют некоторые данные, связанные с соответствующим идентификатором.

Как я могу перестроить линию так, чтобы она была отсортирована по ID?

string 1 4 2 2 3 3 

Примечание: строка может содержать любое количество идентификаторов, в отличие от примера.

Используя сценарий оболочки, я имею в виду что-то вроде

while read n  
do 
    echo $(echo $n | sork -k (... stuck here)) 
done < infile 
+0

Во-первых, вы не можете сортировать одну строку. Попробуйте циклически перемещаться по данным и размещать их в массиве, основанном на нечетной цифре (если вы правы, и они уникальны) – grail

ответ

1

Как Баш скрипт это может быть сделано с:

Код:

#!/usr/bin/env bash 

# send field pairs as separate lines 
function emit_line() { 
    while [ $# -gt 0 ] ; do 
     echo "$1" "$2" 
     shift; shift 
    done 
} 

# break the line into pieces and send to sort 
function sort_line() { 
    echo $1 
    shift 
    emit_line $* | sort 
} 

# loop through the lines in the file and sort by key-value pairs 
while read n; do 
    echo $(sort_line $n) 
done < infile 

Файл infile:

string 2 2 3 3 1 4 
string 2 2 0 3 4 4 1 7 
string 2 2 0 3 2 1 

Выход:

string 1 4 2 2 3 3 
string 0 3 1 7 2 2 4 4 
string 0 3 2 1 2 2 

Update:

списывание рода от grail's version, чтобы удалить (гораздо медленнее) внешний вид:

function sort_line() { 
    line="$1" 
    shift 

    while [ $# -gt 0 ] ; do 
     data[$1]=$2 
     shift; shift 
    done 

    for i in ${!data[@]}; do 
     out="$line $i ${data[i]}" 
    done 
    unset data 
    echo $line 
} 

while read n; do 
    sort_line $n 
done < infile 
1

Вы можете использовать Python для этого. Эта функция разбивает столбец на listtuples, который затем может быть отсортирован. itertools.chain затем используется для повторной сборки пар значений ключей.

Код:

import itertools as it 

def sort_line(line): 
    # split the line on white space 
    x = line.split() 

    # make a tuple of key value pairs 
    as_tuples = [tuple(x[i:i+2]) for i in range(1, len(x), 2)] 

    # sort the tuples, and flatten them with chain 
    sorted_kv = list(it.chain(*sorted(as_tuples))) 

    # join the results back into a string 
    return ' '.join([x[0]] + sorted_kv) 

Код проверки:

data = [ 
    "string 2 2 3 3 1 4", 
    "string 2 2 0 3 4 4 1 7", 
] 

for line in data: 
    print(sort_line(line)) 

Результаты:

string 1 4 2 2 3 3 
string 0 3 1 7 2 2 4 4 
2

Другой Баш альтернатива, которая не зависит от того, сколько иды есть:

#!/usr/bin/env bash 

x='string 2 2 3 3 1 4' 
out="${x%% *}" 

in=($x) 

for ((i = 1; i < ${#in[*]}; i += 2)) 
do 
    new[${in[i]}]=${in[i+1]} 
done 

for i in ${!new[@]} 
do 
    out="$out $i ${new[i]}" 
done 

echo $out 

Вы можете поместить петлю вокруг участка, если вы хотите прочитать файл

2

Я добавлю gawk solu в ваш длинный список опций.

Это автономный скрипт:

#!/usr/bin/env gawk -f 

{ 
    line=$1 

    # Collect the tuples into values of an array, 
    for (i=2;i<NF;i+=2) a[i]=$i FS $(i+1) 

    # This sorts the array "a" by value, numerically, ascending... 
    asort(a, a, "@val_num_asc") 

    # And this for loop gathers the result. 
    for (i=0; i<length(a); i++) line=line FS a[i] 

    # Finally, print the line, 
    print line 

    # and clear the array for the next round. 
    delete a 
} 

Это работает путем копирования ваших кортежей в массив, сортировка массива, а затем повторную сборку отсортированные кортежи в цикле, который печатает элементы массива.

Обратите внимание, что это gawk-only (не традиционный awk) из-за использования asort().

$ cat infile 
string 2 2 3 3 1 4 
other 5 1 20 9 3 7 
$ ./sorttuples infile 
string 1 4 2 2 3 3 
other 3 7 5 1 20 9 
+0

это кажется отличной идеей. посмотрит, как работает gawk – namesake22

Смежные вопросы