5

How does one sort an array based on a substring of each element ?
e.g. given an array like

arr=( 2some05stuff 4more02stuff 3evenmore01stuff 1no04stuff )

I'd like to sort the elements by the numerical string that precedes stuff so I end up with

3evenmore01stuff
4more02stuff
1no04stuff
2some05stuff

I know that parameter expansion flags o/O reorder an array e.g.

print -rl "${(@on)arr}"
1no04stuff
2some05stuff
3evenmore01stuff
4more02stuff

and

print -rl "${(@On)arr}" 
4more02stuff
3evenmore01stuff
2some05stuff
1no04stuff

I just don't know if it's possible to combine them flags with a function or other parameter expansion like e.g. subscript removal or subscript expansion...

3

I don't know of a way to do this inline. With globs qualifiers, you can specify a sort key (*(oe\''REPLY=${${REPLY%stuff*}##*[^0-9]}'\')), but there's no such thing with parameter expansion modifiers.

What you can do is build an auxiliary array containing ${sort_key}$'\0'${value}, i.e. append a null byte and the original value to the sort key. Assuming that the sort keys don't contain null bytes, sorting that array gives the desired order, and stripping off the sort key prefix gives the desired result.

typeset -a tmp; tmp=(); typeset -i i
for ((i=1; i<=$#arr; i++)); do tmp[$i]=${${arr[$i]%stuff*}##*[^0-9]}$'\0'$arr[$i]; done
print -lr "${(@)${(@o)tmp}#*$'\0'}"
  • thanks ! indeed, with globs it's easy job (my Q was initially a comment here); it would have been cool to do the same with arrays... – don_crissti Dec 16 '16 at 18:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.