【问题标题】:How to merge two arrays in a zipper like fashion in Bash?如何在 Bash 中以类似拉链的方式合并两个数组?
【发布时间】:2015-08-23 15:18:45
【问题描述】:

我正在尝试以类似拉链的方式将两个数组合并为一个。我很难做到这一点。

array1=(one three five seven)
array2=(two four six eight)

我尝试过使用嵌套的 for 循环,但无法弄清楚。我不希望输出是 13572468 而是 12345678。

我正在处理的实际脚本在这里 (http://ix.io/iZR).. 但它显然没有按预期工作。我要么打印整个array2(例如124683),要么只打印第一个索引,如果循环不起作用(例如12325272)。

那么我如何得到输出:

one two three four five six seven eight

上面有两个数组?

编辑:我能够使用两个 for 循环和 paste (http://ix.io/iZU) 来解决它。看看有人是否有更好的解决方案仍然很有趣。所以如果你有时间,请看一下。

【问题讨论】:

  • 为什么需要嵌套for循环?一个循环级别就足够了:循环索引到两个长度中较小的一个。
  • @4ae1e1 我想我可以让它像那样工作。我需要循环来构建索引,就像我在解决方案中所做的那样。
  • 对不起,我不阅读完整的脚本,尤其是当它们不是很可读的时候。不确定您所说的“建立索引”是什么意思。
  • @4ae1e1 第一个循环将输出温度和条件(例如 10°C \u2601)。第二个将输出有效时间(例如 10:00)。我使用循环将它们排列成我想要的正确格式。因此,我将有两个索引“列表”,可以这么说。
  • “两个索引列表”:我想大多数人都说 elements 的两个数组(“列表”很好,尽管在 Bash 中说数组是正确的 jagon) . “索引”是一个下标。您的意思是“构建数组”,而不是“构建索引”。

标签: arrays bash zsh


【解决方案1】:

这是基于RTLinuxSWanswer,对Paused until further noticecomment 进行了改进,增加了对稀疏和关联数组的支持。

for index in "${!array1[@]}"; do  # Also, quote indices
    result+=( "${array1[$index]}" "${array2[$index]}" )
done

之后:

$ echo "${result[@]}"
one two three four five six seven eight
$ declare -p result
declare -a result=([0]="one" [1]="two" [2]="three" [3]="four" [4]="five" [5]="six" [6]="seven" [7]="eight")

这假设两个数组的索引是相同的。

【讨论】:

    【解决方案2】:

    假设两个数组大小相同,

    unset result
    for (( i=0; i<${#array1[*]}; ++i)); do
        result+=( "${array1[$i]}" "${array2[$i]}" )
    done
    

    【讨论】:

    • 请注意,这种方法假定索引从零到数组的长度(减一)。由于 Bash 支持稀疏数组,因此这是行不通的。此外,它不适合关联数组。要迭代索引,请使用for index in ${!array1[@]}。此外,您应该习惯使用[@] 而不是[*]。后者,如果引用,则使数组成为一个字符串,由$IFS 的第一个字符分隔。比较 (IFS=XYZ; a=("red ball" "blue sky" "green grass"); for e in "${a[@]}"; do echo "$((i++)) $e"; done) 与相同的星号而不是 at 符号。
    • @Paused 谢谢!我发布了my own answer 采纳了您的建议。
    【解决方案3】:

    以下解决方案旨在处理数据由换行符分隔:每个值在每个文件的单独行中加载到数组中。可以完美运行,但如果您的数据组织方式不同,请参阅 @Socowi 在 cmets 中使用 pasteprintf 的替代方案。非常感谢@Socowi 提出问题并为以其他方式分隔的数据提供解决方法! 更新>

    这是另一种交错来自 (2) 个数组的数据的解决方案,这些数组填充了由单独文件中的换行符分隔的数据。此方案使用pasteecho & xargs

    数组数据:我将文件提供给数组,因为我喜欢从代码中分解数据。 readarray 将使用以下每个值由换行符分隔的文件:

    test1.txt

    one
    three
    five
    seven
    

    test2.txt

    two
    four
    six
    eight
    

    把它们放在一起:

    #!/bin/bash
    
    readarray arrayTest1 < /root/test1.txt
    readarray arrayTest2 < /root/test2.txt
    
    paste <( echo "${arrayTest1[*]}" ) <( echo "${arrayTest2[*]}" ) | xargs
    

    输出:

    one two three four five six seven eight
    

    【讨论】:

    • 使用paste 是个好主意。但目前实施并不整洁。它假定每个条目都以换行符结尾并且不包含空格或反斜杠。我认为以下命令应该可以可靠地工作:paste -zd ' ' &lt;(printf %s\\0 "${a[@]}") &lt;(printf %s\\0 "${b[@]}") | tr '\0' ' '(将' ' 都替换为要使用的输出分隔符。请注意,总是有一个尾随分隔符可以被... | head -c-1 删除)。不幸的是,即使这样也不能用于可靠地将输出再次读入数组,因为paste 不能为-d 使用空字节。
    • @Socowi 非常感谢!我已将您的反馈纳入帖子中。非常感谢您抽出宝贵时间制定出适用于其他数据类型的替代解决方案!非常感谢您的所有反馈!
    【解决方案4】:

    您可以轻松读取文件,使用其内容创建一个数组,检查谁是较大的并创建循环。

    #!/usr/bin/env bash
    
    ## Writting a until d into the file file01 and writing 1 until 3 into the file file02.
    echo {a..d} | tee file01
    echo {1..3} | tee file02
    
    ## Declaring two arrays (FILE01 and FILE02) and a variable as integer.
    declare -a FILE01=($(<file1))
    declare -a FILE02=($(<file2))
    declare -i COUNT=0
    
    ## Checking who is the biggest array and declaring the ARRAY_SIZE.
    [[ "${#FILE01[@]}" -ge "${#FILE02[@]}" ]] && declare -i ARRAY_SIZE="${#FILE01[@]}" || declare -i ARRAY_SIZE="${#FILE02[@]}"
    
    ## Creating the loop (COUNT must be lesser or equal ARRAY_SIZE) and print each element of each array (FILE01 and FILE02).
    while [ ${COUNT} -le ${ARRAY_SIZE} ]; do
      echo -n "${FILE01[$COUNT]} ${FILE02[$COUNT]} "
      ((COUNT++))
    done
    

    declare -a -> 创建一个数组

    declare -i -> 将 var 声明为整数

    ${#FILE01[@]} -> 获取数组大小

    【讨论】:

      【解决方案5】:

      我发现更常见的情况是我想将两个数组压缩到 两列。这不像“RTLinuxSW”答案那样原生 Zsh,但是 对于这种情况,我使用粘贴。

      % tabs 16
      % paste <(print -l $array1) <(print -l $array2)
      one     two
      three   four
      five    six
      seven   eight
      

      然后可以将其推入另一个数组以获得预期的输出:

      % array3=( `!!`«tab»«tab» )
      % print $array3
      one two three four five six seven eight
      

      【讨论】:

      • 您可以使用 trcut 将其变成单行:paste &lt;(print -l $array1) &lt;(print -l $array2) | tr -s "[:space:]" ' ' | cut -d' ' -f1-
      猜你喜欢
      • 2020-12-07
      • 2010-12-31
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多