Zsh

如何從數組數組中檢索項目?

  • April 27, 2021

您好 StackExchange 專業人士!

我正在為 macOS 開發一個 zsh 項目。我使用 typeset 創建了三個關聯數組來保存值,並使用第四個數組來引用各個數組。是否可以遍歷 arrCollection 以從每個成員數組中檢索鍵/值對?請注意,下面數組中的鍵與我的生產腳本不同——它們只是鍵索引,而不是您可能在關聯數組中找到的更具描述性的鍵。

我想我可以像這樣使用參數擴展:

for k in $(sort <<< "${(kvF)arrCollection}"); do
  echo "$arrCollection["${(kvF)k}"]"
done

不過我說的不太對。任何人都可以幫忙嗎?預期的輸出將是由換行符分隔的所有三個數組中的所有項目的列表。

下面的完整腳本範例。用法:arrTest.sh showAll

#!/bin/zsh

key=$1

typeset -A arrOne arrTwo arrThree
typeset -A arrCollection

#Plan is to use an array of arrays so that a for loop can be used later to loop
#through each key/value pair looking for a value that matches some pattern in an if statement
#(if statement not included here). In the showAll case, how can I use parameter expansion to print all
#of the values in each array? The if statement will further constrict what is actually echoed based on its
#value.

arrOne[1]="First"
arrOne[2]="Second"
arrOne[3]="Third"
arrOne[4]="Fourth"

arrTwo[1]="Purple"
arrTwo[2]="Orange"
arrTwo[3]="Red"
arrTwo[4]="Green"
arrTwo[5]="Blue"

arrThree[1]="First"
arrThree[2]="Red"
arrThree[3]="Planet"
arrThree[4]="Sun"
arrThree[5]="Moon"
arrThree[6]="Star"

#Array of arrays
arrCollection[1]=arrOne
arrCollection[2]=arrTwo
arrCollection[3]=arrThree

#Expect a parameter
if [ -z "$key" ]
then
   echo "Please enter a parameter"
else
   case "$key" in
   showAll)
       for k in $(sort <<< "${(kvF)arrCollection}"); do
           #This is the part I am having trouble with
           echo "$arrCollection["${(kvF)k}"]"
       done
       exit 1
   ;;
   *)
       echo "Something goes here"
       exit 1
   ;;
   esac
fi

當您的鍵是從一開始的連續十進制數字時,不確定為什麼要使用關聯數組而不是普通數組,但是如果我正確理解您想要的內容,您可以這樣做:

for key in "${(nok@)arrCollection}"; do
 print -r - "Assoc $key: $arrCollection[$key]"
 printf ' "%s" => "%s"\n' "${(@kvP)arrCollection[$key]}"
done

您的樣本上應該給出如下內容:

Assoc 1: arrOne
"3" => "Third"
"4" => "Fourth"
"1" => "First"
"2" => "Second"
Assoc 2: arrTwo
"3" => "Red"
"4" => "Green"
"5" => "Blue"
"1" => "Purple"
"2" => "Orange"
Assoc 3: arrThree
"3" => "Planet"
"4" => "Sun"
"5" => "Moon"
"6" => "Star"
"1" => "First"
"2" => "Red"

或者也可以按鍵對每個關聯的成員進行數字排序:

for key in "${(nok@)arrCollection}"; do
 print -r - "Assoc $key: $arrCollection[$key]"
 for assoc_key in "${(@knoP)arrCollection[$key]}"; do
   printf ' "%s" => "%s"\n' "$assoc_key" "${${(P)arrCollection[$key]}[$assoc_key]}"
 done
done

這會給:

Assoc 1: arrOne
"1" => "First"
"2" => "Second"
"3" => "Third"
"4" => "Fourth"
Assoc 2: arrTwo
"1" => "Purple"
"2" => "Orange"
"3" => "Red"
"4" => "Green"
"5" => "Blue"
Assoc 3: arrThree
"1" => "First"
"2" => "Red"
"3" => "Planet"
"4" => "Sun"
"5" => "Moon"
"6" => "Star"

上面的鍵使用o(順序)和n(數字)參數擴展標誌進行排序。除了由十進制數字序列組成的部分之外,元素使用區域設置排序順序進行比較。十進制數字序列被解釋為十進制整數並進行數字比較。

這類似於 GNU 實現對/選項sort所做的事情。-V``--version-sort

例如so foo2-3would come beforefoo10-3和 before foo2-10,但不能用於正十進制整數以外的數字(-2也將出現 before-102.3before 2.10)。

要使用其他任意標准進行排序,雖然在 zsh 中以內置方式進行排序有很複雜的方法,但sort如果您可以保證元素不包含 NL 或 NUL 字元並且不為空,則可能更容易使用。

以 GNU 為例sort

for key in ${(0)"$(print -rNC1 -- ${(k)arrCollection} | sort -zg)"}

以數字方式循環非空鍵,但這次支持各種數字表示(包括 0x20、1e-1、無窮大、-20、0x3.fp5…)。

上面是使用 NUL 分隔的記錄來提供列表sort並拆分其輸出,因此假設鍵不包含 NUL 字元。要改用 NL/LF 字元,請刪除-N,-z並更改(0)(f).


¹ 和 NUL 字元必須單獨處理,因為標準比較 API 會阻塞它。

引用自:https://unix.stackexchange.com/questions/646837