Home > Back-end >  How to avoid skipping items in a list in zsh?
How to avoid skipping items in a list in zsh?

Time:12-03

I am using zsh on Mac. I created a list subjects of say 25 items in that list. Now, I would like to run all possible pairwise comparisons between the items in the list, e.g., subject1 vs. subject2, but without running repeated measurements (such as subject1 vs. subject2 and subject2 vs subject1) Here is my code for this task:

subjects=(Subject1 Subject2 Subject4 Subject5 Subject6 Subject7 Subject8 Subject9 Subject10 Subject11 Subject12 Subject13 Subject14 Subject15 Subject16 Subject17 Subject18 Subject19 Subject20 Subject22 Subject23 Subject24 Subject25)
for i in $subjects
do
for j in $subjects
do
if [[ $i < $j ]]
then
echo "Processing pair $i - $j ..."
fi
done
done

The problem is that zsh skips the subjects from subject10 to subject19 and directly jumps to subject20 after comparing subject1 vs. subject9. Where is the flaw in my code?

CodePudding user response:

The issue is with the comparison operator used in the conditional statement if [[ $i < $j ]]. The < operator compares the strings lexicographically, i.e., it compares the ASCII value of the characters in the strings. In ASCII, the value of the character '1' is less than the value of the character '9', so the strings "Subject10" to "Subject19" are considered to be less than "Subject9", and the comparison between "Subject1" and "Subject10" to "Subject19" is skipped.

To fix this issue, you could use a numerical comparison operator -lt, which compares the values of the variables as integers. First, you need to extract the numerical part of the strings by using parameter expansion, and then use the -lt operator to compare the numerical values. Here's the modified code:

subjects=(Subject1 Subject2 Subject4 Subject5 Subject6 Subject7 Subject8 Subject9 Subject10 Subject11 Subject12 Subject13 Subject14 Subject15 Subject16 Subject17 Subject18 Subject19 Subject20 Subject22 Subject23 Subject24 Subject25)

for i in $subjects
do
  for j in $subjects
  do
    # Extract the numerical part of the strings
    i_num=${i#Subject}
    j_num=${j#Subject}

    # Use the -lt operator to compare the numerical values
    if [[ $i_num -lt $j_num ]]
    then
      echo "Processing pair $i - $j ..."
    fi
  done
done

This should give you the expected output.

  • Related