2016-01-25 45 views
1

說我有陣列刪除(不只是未設置)從數組中多個字符串不知道它們的位置

a1=(cats,cats.in,catses,dogs,dogs.in,dogses) 
a2=(cats.in,dogs.in) 

我想刪除一切從A1在A2字符串刪除「在」匹配後,在除了完全匹配的那些(包括「.in」)之外。

因此,從a1中,我想刪除貓,cats.in,dog,dogs.in,但不是catses或dogses。

我想我必須分兩步來做。我發現如何削減了「在」走:

for elem in "${a2[@]}" ; do 
    var="${elem}" 
    len="${#var}" 
    pref=${var:0:len-3} 
done 

^這給了我‘貓’和‘狗’

我需要什麼樣的命令添加到循環刪除每個ELEM從A1?

+0

的可能重複:HTTP://計算器。 com/questions/2696055 /雙列表中的交叉點 – user2182349

+0

只需使用'unset'即可。這會留下像'0,2,3,4,6'這樣的索引,並從'a1'移除索引'1,5'。然後運行'a1 =(「$ {a1 [@]}」)',將這些索引設置爲'0..4'。 – anishsane

+1

另外,在另一個說明中,數組中的默認分隔符是空格,而不是逗號。 – anishsane

回答

1

這是我去的解決方案:

for elem in "${a2[@]}" ; do 
    var="${elem}" 
    len="${#var}" 
    pref=${var:0:len-3} 

    #set 'cats' and 'dogs' to ' ' 
    for i in ${!a1[@]} ; do 
      if [ "${a1[$i]}" = "$pref" ] ; then 
       a1[$i]='' 
      fi 

    #set 'cats.in' and 'dogs.in' to ' ' 
      if [ "${a1[$i]}" = "$var" ] ; then 
       a1[$i]='' 
      fi 
    done 
done 

然後,我創建了從A1的新數組沒有'元素

a1new=() 
for filename in "${a1[@]}" ; do 
    if [[ $a1 != '' ]] ; then 
     a1new+=("${filename}") 
    fi 
done 
1

一個天真的做法是:

#!/bin/bash 

# Checkes whether a value is in an array. 
# Usage: "$value" "${array[@]}" 
inarray() { 
    local n=$1 h 
    shift 
    for h in "[email protected]";do 
     [[ $n = "$h" ]] && return 
    done 
    return 1 
} 

a1=(cats cats.in catses dogs dogs.in dogses) 
a2=(cats.in dogs.in) 
result=() 

for i in "${a1[@]}";do 
    if ! inarray "$i" "${a2[@]}" && ! inarray "$i" "${a2[@]%.in}"; then 
     result+=("$i") 
    fi 
done 

# Checking. 
printf '%s\n' "${result[@]}" 

如果你只想要打印的值標準輸出,你可能反而要使用comm

comm -23 <(printf '%s\n' "${a1[@]}"|sort -u) <(printf '%s\n' "${a2[@]%.in}" "${a2[@]}"|sort -u) 
1

在我看來,在解決此問題的最簡單方法是嵌套for迴路:

#!/usr/bin/env bash 

a1=(cats cats.in catses dogs dogs.in dogses) 
a2=(cats.in dogs.in) 

for x in "${!a1[@]}"; do    # step through a1 by index 
    for y in "${a2[@]}"; do    # step through a2 by content 
    if [[ "${a1[x]}" = "$y" || "${a1[x]}" = "${y%.in}" ]]; then 
     unset a1[x] 
    fi 
    done 
done 

declare -p a1 

但取決於你的實際的數據,以下可能會更好,使用兩個單獨的for循環代替嵌套。

#!/usr/bin/env bash 

a1=(cats cats.in catses dogs dogs.in dogses) 
a2=(cats.in dogs.in) 

# Flip "a2" array to "b", stripping ".in" as we go... 
declare -A b=() 
for x in "${!a2[@]}"; do 
    b[${a2[x]%.in}]="$x" 
done 

# Check for the existence of the stripped version of the array content 
# as an index of the associative array we created above. 
for x in "${!a1[@]}"; do 
    [[ -n "${b[${a1[x]%.in}]}" ]] && unset a1[$x] a1[${x%.in}] 
done 

declare -p a1 

這裏的好處是那,而不是通過所有的a2每個項目在a1一次在每個陣列循環,你只是循環。羽絨側面可能取決於您的數據。例如,如果a2的內容非常大,則可能會達到內存限制。當然,我不能從你提到的問題中知道這一點。此解決方案適用於您提供的數據。

注意:此解決方案還取決於關聯數組,這是在版本4中引入bash的功能。如果您運行的是舊版本的bash,現在可能是升級的好時機。 :)

相關問題