1

I need to delete specific values in an array (which vary in their index positions), similar to the splice function in javascript.

Example:

set -A ARRAY1 "a" "b" "c" "d" "e"
set -A ARRAY2 "a" "c" "e"

# Expected ARRAY1 after splice: "b" "d"

What I've tried:

I iterated through the arrays to find matches to the values I want deleted, and set them to empty ("").

ITERATION=0
for i in "${ARRAY1[@]}"
do
    for j in "${ARRAY2[@]}"
    do
        if [[ $i == $j ]]
        then
            ARRAY1[$ITERATION]=""
        fi
    done
    ITERATION=$((ITERATION+1))
done

#ARRAY1 after emptying values: "" "b" "" "d" ""

After that, I made a variable to store the concatenation of the first array's values.

VARIABLE=${ARRAY1[@]}

Then set the array back together again.

set -A ARRAY1 $VARIABLE
# VARIABLE: b d

Now the ARRAY1 has 2 indexes with values "b" and "d" as expected.

echo "ARRAY1: ${ARRAY1[@]}"
# output: ARRAY1: b d

I tried searching for the correct way to do this but couldn't find anything, and I think my solution is not right, even if it seems to work. Is there a correct or better way to do this? Is there a function for this in ksh?

Thanks in advance!

  • have you tried `unset ARRAY1[$ITERATION]` ? – markp-fuso May 20 '20 at 17:44
  • I tried just after reading your answer, and it works! Thanks mark, I had the wrong idea of how the 'unset' command works. Now I'm trying to make Glenn's answer work too, but I think it's on a different syntax, it keeps giving me syntax errors. – Lobsang Daniel Barriga Tapia May 22 '20 at 20:08
  • In bash you could do something like `ARRAY1=( $(grep -Fxvf <(printf "%s\n" ${ARRAY2[@]}) <(printf "%s\n" ${ARRAY1[@]}) ) )`. I do not know how to translate this into `ksh`, but it might help. – Walter A May 24 '20 at 08:59

2 Answers2

0

So, what you want to do is take the difference of sets. An indexed array is not a good representation of a set. However, the keys of an associative array is.

Try this:

array1=( "a" "b" "c" "d" "e" )
array2=( "a" "c" "e" )

# declare an associative array
typeset -A tmp                    

# populate it
for elem in "${array1[@]}"; do
  tmp[$elem]=1
done

# remove elements
for elem in "${array2[@]}"; do
  unset "tmp[$elem]"
done

# reassign the array with the keys of the assoc. array
array1=( "${!tmp[@]}" )

printf "%s\n" "${array1[@]}"
b
d

Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

Using the same notation as the OP, just need one small change to the if/then block to unset the array position:

ITERATION=0
for i in "${ARRAY1[@]}"
do
    for j in "${ARRAY2[@]}"
    do
        if [[ $i == $j ]]
        then
            unset ARRAY1[$ITERATION]
        fi
    done
    ITERATION=$((ITERATION+1))
done

Here's a ksh fiddle of the above.

A quick dump of the current array:

echo "ARRAY1: ${ARRAY1[@]}"
ARRAY1: b d
markp-fuso
  • 28,790
  • 4
  • 16
  • 36