Trier les lignes par nombre de mots par ligne

14

Contribution donnée:

hello: world foo bar baz
bar:
baz: bin boop bop fiz bang beep
bap: bim bam bop
boatkeeper: poughkeepsie

Je voudrais le trier dans la plupart des mots en haut, au moins à la fin, comme ceci:

baz: bin boop bop fiz bang beep
hello: world foo bar baz
bap: bim bam bop
boatkeeper: poughkeepsie
bar:

Comment pourrais-je faire cela avec sortun autre outil?

Caleb Xu
la source
Juste pour être clair, vous voulez trier par nombre de mots et non par longueur de ligne (avec votre entrée d'échantillon, la ligne avec le plus de mots est également la plus longue mais ce n'est pas toujours le cas)?
don_crissti
Oui. La ligne avec le plus de mots n'est pas nécessairement la plus longue en général. par exemple, je veux bin: bop boopavant boatkeeper: poughkeepsie. Si deux lignes partagent le même nombre de mots, je préférerais que les liens soient alphabétisés, mais ce n'est pas une exigence.
Caleb Xu

Réponses:

22

Vous pourriez faire quelque chose comme:

awk '{print NF,$0}' file | sort -nr | cut -d' ' -f 2-

Nous utilisons awkpour préfixer le nombre de champs à chaque ligne. Nous avons ensuite sortpar ce numéro et le retirer avec cut.

Cœur sombre
la source
Cela a fonctionné. Je me demandais pourquoi l'ordre a été inversé, mais je vois votre modification maintenant.
Caleb Xu
6

Dans GNU récent, awkon peut utiliser un PROCINFOtableau pour définir de nombreux paramètres internes, y compris l'ordre dans lequel les éléments du tableau sont imprimés (contrôlés par élément "sorted_in"). Ainsi, nous pouvons construire et tableau indexé avec la valeur de NF" "NR, quels éléments ont une valeur de $0et l'imprimer dans la sortie souhaitée, dans votre cas, ce serait "@ind_num_desc":

awk '{a[NF" "NR]=$0}END{PROCINFO["sorted_in"]="@ind_num_desc"; for(i in a) print a[i]}' file
jimmij
la source
1
+1 pensait la même chose: cependant, il faut peut-être noter que cela aura pour effet secondaire de
dédupliquer
@steeldriver vous avez absolument raison, j'ai édité ma réponse, ça devrait aller maintenant.
jimmij
Cela préserve désormais l'ordre d'origine entre les enregistrements avec le même nombre de champs, au lieu de trier les mots comme une clé de tri secondaire. Si vos clés l'étaient NF" "$0" "NR, vous n'auriez qu'un NRmécanisme de secours / de gestion des doublons.
Peter Cordes
1
@PeterCordes mais cela inverserait l'ordre des mots, je ne vois aucun moyen de résoudre les liens par ordre alphabétique autre que par définition propre fonction cmp_func()- gnu awk le permet.
jimmij
5

Perl one-liner:

print sort { split(' ',$a) <=> split(' ',$b) } <>;

Si vous souhaitez rompre les liens en utilisant l'ordre alphabétique:

print sort { split(' ',$a) <=> split(' ',$b) or $a cmp $b } <>;
Nate Eldredge
la source
4

Par python.

s = '''hello: world foo bar baz
bar:
baz: bin boop bop fiz bang beep
bap: bim bam bop'''.splitlines()
for i in sorted(s, key=lambda x: len(x.split()), reverse=True):
    print(i)

ou

with open('/path/to/the/input/file') as f:
    m = f.readlines()
    for i in sorted(m, key=lambda x: len(x.split()), reverse=True):
        print(i, end="")
Avinash Raj
la source