排序传递给函数作为参数的阵列 [英] Sorting an array passed to a function as parameter
问题描述
我想对数组排序了一些辅助功能,那我就可以
每当我需要它来使用。所以我做了这样的事情。它的工作原理。
#!的/ usr /斌/庆典#排序给出的参数数组
功能array_sort { 声明-a source_array =($ {!1})
sorted_array =($(在elmnt$ {source_array [@]};做回声$ elmnt;完成|排序))
回声$ {sorted_array [@]}#不会呼应到标准输出,因为赋值给一个变量
}# 测试用例#原单阵列
ARR =(C B A 3 2 1)#assign函数调用给一个变量
分类= $(array_sort改编[@])#回声出结果
回声$ {分类[@]}
我的问题是,有没有这样做,在返回从函数数组元素方面的一些更好的(清洁剂)的方式(不执行更好的排序算法)?
如果你想有一个强大的排序功能(即,一个将处理空格和换行完美),你可能会考虑实施猛砸排序算法:这里有一个快速排序。
快速排序(){
#排序位置元件WRT字母排序
#返回的是数组quicksort_ret
如果(($#== 0));然后
quicksort_ret =()
返回
科幻
局部轴= $ 1时=()=低()我
转移
对于i;做
如果[$我< $支点]];然后
低+ =($ I)
其他
更大+ =($ I)
科幻
DONE
快速排序$ {更大[@]}
更大=($ {quicksort_ret [@]})
快速排序$ {较低[@]}
quicksort_ret + =($支点$ {更大[@]})
}
$快速排序C B A 3 2 1
$ printf的'%s的\\ n'$ {quicksort_ret [@]}
1
2
3
一个
b
C
您可以更改顺序测试中的行
如果[$我< $支点]];然后
通过任何你喜欢的。例如,数值只排序,你会使用
IF((I<枢));然后
您甚至可以使用一个变量(例如,quicksort_order),将扩大到排序功能。在这种情况下,通过更换前行
如果$ quicksort_order$ I$支点;然后
和搭配,例如使用的,如果你想字母排序:
order_alnum(){[[$ 1< $ 2]]; }
quicksort_order = order_alnum
的快速排序
函数使用的输入和位置参数变量 quicksort_ret
输出。它现在微不足道,使包装解决这个函数来处理数组名作为输入。
有关,像你的,使用排序
,但修复了通配符和空间的问题(但不换行解决问题)的方法。使用内置的映射文件
,所以这只是Bash≥4。对于bash< 4,有其他解决方法(但你不应该使用bash 4;再反正)。
#!的/ usr /斌/庆典#排序给出的参数数组
#返回的是数组sorted_array
array_sort(){
映射文件-t sorted_array< ≤(printf的'%S \\ n'{!1} $|排序)
}#TEST CASE 1
回声测试1
#原数组
ARR =(C B A 3 2 1)
#数组排序
array_sort常用3 [@]
#显示阵列
声明-psorted_array#TEST CASE 2
回声测试2
#原数组
ARR =('*''这个领域的空间)
#数组排序
array_sort常用3 [@]
#显示阵列
声明-psorted_array#TEST CASE 3(失败)
回声测试3
#原数组
ARR =($'有\\钠换行符\\ n在这阵)
#数组排序
array_sort常用3 [@]
#显示阵列
声明-psorted_array
将输出:
测试1
声明-a sorted_array ='([0] =1[1] =2[2] =3[3] =一个[4] =b的[5] =C)
测试2
声明-a sorted_array ='([0] =*[1] =在这一领域的空间)'
测试3
声明-a sorted_array =([0] =换行[1] =此数组中的[2] =有)'
回答您的问题评论:
这样一来我就必须知道
sorted_array
变量的名称,使用它在我的脚本。可以在避免?
块引用>如果你想给排序数组的名称,修改
array_sort
为:array_sort(){
#$ 1数组名称进行排序(与尾随[@])
#$ 2是返回数组的名称(不带[@])
#注:输出数组的名字可以命名输入数组
映射文件-t$ 2< ≤(printf的'%S \\ n'{!1} $|排序)
}和使用:
$ a =(A GëžĴR)
$ array_sort一[@]a_sorted
$申报-p a_sorted
声明-a a_sorted ='([0] =一个[1] =e的[2] =G[3] =J[4] =R[5] =Z)如果你想使用
快速排序
函数从我的第一个答案,你会使用一个包装函数(这个名字不好意思)(*)quicksort_gniourf(){
#$ 1数组名称进行排序(与尾随[@])
#$ 2是返回数组的名称(不带[@])
#注:输出数组的名字可以命名输入数组
#这是围绕快速排序功能的包装函数
快速排序$ {!1}
当地的K = 0 V
声明-g$ 2 =()
在V$ {quicksort_ret [@]};做
printf的-v$ 2 [$ K]'%s'的$ V
((+ K))
DONE
}和(在这里我使用的输入和输出相同的数组名)是:
$ a =(A GëžĴR)
$ quicksort_gniourf一个[@]一
$声明-p一
声明-a一个='([0] =一个[1] =e的[2] =G[3] =J[4] =R[5] =Z)'
此外,你会如何回应出结果数组,preventing
的扩展*
与声明-p
它是确定,但与的printf
或回声它扩展了文件名?
块引用>要打印一个数组
阵列
使用回声
擅自扩大通配符(注意引号):回声$ {数组[@]}
和使用
的printf
,每行一个字段(注意引号):的printf'%s的\\ n'$ {数组[@]}
(*)由于@konsolebox提到在他的评论,
声明-g
出现在bash 4.2。您可以替换的eval$ 2 =()
如果你喜欢(它在,因为这一点是相当安全的$ 2
被认为是一个变量名反正)。I wanted to have some helper function for array sorting, that I would be able to use whenever I need it. So I did something like this. It works.
#!/usr/bin/bash # sorts an array given as param function array_sort { declare -a source_array=("${!1}") sorted_array=($(for elmnt in "${source_array[@]}"; do echo $elmnt; done | sort)) echo "${sorted_array[@]}" # wont echo to stdout, because of assignment to a variable } # TEST CASE # orginal array arr=(c b a 3 2 1) #assign function call to a variable sorted=$(array_sort arr[@]) # echo-out the results echo ${sorted[@]}
My question is, is there some better(cleaner) way of doing this, in terms of returning array elements from function (not implementing better sorting algorithm)?
解决方案If you want a robust sorting function (i.e., one that will deal with spaces and newlines flawlessly), you may consider implementing a sorting algorithm in Bash: here's a quicksort.
quicksort() { # sorts the positional elements wrt alphanumerical sort # return is in array quicksort_ret if (($#==0)); then quicksort_ret=() return fi local pivot=$1 greater=() lower=() i shift for i; do if [[ "$i" < "$pivot" ]]; then lower+=( "$i" ) else greater+=( "$i" ) fi done quicksort "${greater[@]}" greater=( "${quicksort_ret[@]}" ) quicksort "${lower[@]}" quicksort_ret+=( "$pivot" "${greater[@]}" ) } $ quicksort c b a 3 2 1 $ printf '%s\n' "${quicksort_ret[@]}" 1 2 3 a b c
You can change the ordering test in the line
if [[ "$i" < "$pivot" ]]; then
by whatever you like. E.g., for numerical only sort, you'd use
if ((i<pivot)); then
You can even use a variable (e.g., quicksort_order) that will expand to an ordering function. In this case, replace the former line by
if $quicksort_order "$i" "$pivot"; then
and use with, e.g., if you want alphanumerical sort:
order_alnum() { [[ $1 < $2 ]]; } quicksort_order=order_alnum
The
quicksort
function uses the positional parameters for input and the variablequicksort_ret
for output. It's now trivial to make a wrapper around this function to handle an array name as input.
For a method that, like yours, uses
sort
but fixes the issues with wildcards and spaces (but doesn't fix issues with newlines). Uses the builtinmapfile
, so this is Bash≥4 only. For Bash<4, there are other workarounds (but you shouldn't be using Bash<4 anymore anyways).#!/usr/bin/bash # sorts an array given as param # return is in array sorted_array array_sort() { mapfile -t sorted_array < <( printf '%s\n' "${!1}" | sort ) } # TEST CASE 1 echo "Test 1" # original array arr=(c b a 3 2 1) # sort array array_sort "arr[@]" # display array declare -p "sorted_array" # TEST CASE 2 echo "Test 2" # original array arr=( '*' 'a space in this field' ) # sort array array_sort "arr[@]" # display array declare -p "sorted_array" # TEST CASE 3 (fails) echo "Test 3" # original array arr=( $'there is\na newline\nin this array' ) # sort array array_sort "arr[@]" # display array declare -p "sorted_array"
will output:
Test 1 declare -a sorted_array='([0]="1" [1]="2" [2]="3" [3]="a" [4]="b" [5]="c")' Test 2 declare -a sorted_array='([0]="*" [1]="a space in this field")' Test 3 declare -a sorted_array='([0]="a newline" [1]="in this array" [2]="there is")'
Answering your questions in comment:
So that way I would have to know the name of that
sorted_array
variable, to use it in my scripts. Can that be avoided?If you want to give the name of the sorted array, modify
array_sort
as:array_sort() { # $1 is the name of array to sort (with the trailing [@]) # $2 is the name of the returned array (without [@]) # Note: name of output array can be name of input array mapfile -t "$2" < <( printf '%s\n' "${!1}" | sort ) }
and use as:
$ a=( a g e z j r ) $ array_sort "a[@]" a_sorted $ declare -p a_sorted declare -a a_sorted='([0]="a" [1]="e" [2]="g" [3]="j" [4]="r" [5]="z")'
If you want to use the
quicksort
function from my first answer, you'd use a wrapper function (sorry about the name)(*):quicksort_gniourf() { # $1 is the name of array to sort (with the trailing [@]) # $2 is the name of the returned array (without [@]) # Note: name of output array can be name of input array # This is a wrapper function around the quicksort function quicksort "${!1}" local k=0 v declare -g "$2=()" for v in "${quicksort_ret[@]}"; do printf -v "$2[$k]" '%s' "$v" ((++k)) done }
and use as (here I'm using the same array name for input and output):
$ a=( a g e z j r ) $ quicksort_gniourf "a[@]" a $ declare -p a declare -a a='([0]="a" [1]="e" [2]="g" [3]="j" [4]="r" [5]="z")'
Also, how would you echo out that resulting array, preventing expansion of
*
, withdeclare -p
it is ok, however withprintf
or echo it expands on filenames?To print an array
array
usingecho
without expanding wildcards (observe the quotes):echo "${array[@]}"
and using
printf
, one field per line (observe the quotes):printf '%s\n' "${array[@]}"
(*) As @konsolebox mentions in his comment,
declare -g
appeared in bash 4.2. You can replace this line witheval "$2=()"
if you like (it's fairly safe at this point since$2
is supposed to be a variable name anyways).这篇关于排序传递给函数作为参数的阵列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!