5

I have an

array1 = (20,30,40,50)
array2 = (10,20,30,80,100,110,40)

I have to get the common values from these 2 arrays in my array 3 like:

array3 = (20,30,40) 

in ascending sorted order.

jaypal singh
  • 74,723
  • 23
  • 102
  • 147
iaav
  • 484
  • 2
  • 9
  • 26

7 Answers7

4

Shell and standard Unix utilities are good at dealing with text files.

In that realm, arrays would be text files whose elements are the lines.

To find the common part between two such arrays, there's the standard comm command. comm expects alphabetically sorted input though.

So, if you have two files A and B containing the elements of those two arrays, one per line (which also means the array elements can't contain newline characters), you can find the intersection with

comm -12 <(sort A) <(sort B)

If you want to start with bash arrays (but using arrays in shells is generally a good indication that you're using the wrong tool for your task), you can convert back and forth between the bash arrays and our text file arrays of lines with printf '%s\n' and word splitting:

array_one=(20 30 40 50)
array_two=(10 20 30 80 100 110 40)
IFS=$'\n'; set -f
intersection=($(comm -12 <(
   printf '%s\n' "${array_one[@]}" | sort) <(
   printf '%s\n' "${array_two[@]}" | sort)))
Stephane Chazelas
  • 5,859
  • 2
  • 34
  • 31
  • 5
    +1. Bare `sort` outputs lexical order: if OP wants numerical order, the `comm` output needs to be passed through `sort -n` – glenn jackman Jun 11 '13 at 01:28
3

You almost certainly should not be using shell for this so here's ONE awk solution to your specific problem:

awk 'BEGIN{
    split("20,30,40,50",array1,/,/)
    split("10,20,30,80,100,110,40",array2,/,/)

    for (i=1;i in array1;i++)
        for (j=1;j in array2;j++)
            if (array1[i] == array2[j])
                array3[++k] = array1[i]

    for (k=1; k in array3; k++)
        printf "array3[%d] = %d\n",k,array3[k]
}'
array3[1] = 20
array3[2] = 30
array3[3] = 40

and if you tell us what you're really trying to do you can get a lot more help.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
2

A pure solution using arrays:

#!/bin/bash

array1=(20,30,40,50)
array2=(10,20,30,80,100,110,40)

IFS=,
for i in $array1 $array2;{ ((++tmp[i]));}
for i in ${!tmp[*]};{ [ ${tmp[i]} -gt 1 ] && array3+=($i);}
echo ${array3[*]}

Output

20 30 40

As array3 is not an associative array, the indexes comes in ascending order using ${!array[*]} notation. If You need comma separated list as input, use echo "${array3[*]}".

It can be used if the source elements are integers. It works only if each of the source arrays contain unique numbers..

TrueY
  • 7,360
  • 1
  • 41
  • 46
  • 1
    To lift confusion, note that `array1=(20,30,40,50)`, even with `IFS=,`, assigns **one** element to `array1`. It's the same as `array1[0]='20,30,40,50'`. However, because of `IFS=,` and because `${array1[*]}` later on is not quoted, that one element is split at that point into `20`, `30`... – Stephane Chazelas Jun 10 '13 at 23:16
  • @sch: Correct! Thanks for the comment! Code modified! – TrueY Jun 10 '13 at 23:28
0

In addition to any of these fine answers, it seems that you also want to sort your array (containing the answer) in ascending order.

You can do that in a number of different ways, including this:

readarray array3 <<<"$(printf "%s\n" "${array3[@]}" | sort -n)"

This method also allows you to filter out duplicate values:

readarray array3 <<<"$(printf "%s\n" "${array3[@]}" | sort -n | uniq)"

And for the sake of the exercise, here's yet another way of solving it:

#!/bin/bash

array1=(20 30 40 50)
array2=(10 20 30 80 100 110 40)
declare -a array3

#sort both arrays
readarray array1 <<<"$(printf "%s\n" "${array1[@]}" | sort -n)"
readarray array2 <<<"$(printf "%s\n" "${array2[@]}" | sort -n)"

# look for values
i2=0
for i1 in ${!array1[@]}; do
    while (( i2 < ${#array2[@]} && ${array1[$i1]} > ${array2[$i2]} )); do (( i2++ )); done
    [[ ${array1[$i1]} == ${array2[$i2]} ]] && array3+=(${array1[$i1]})
done


echo ${array3[@]}
Sir Athos
  • 9,403
  • 2
  • 22
  • 23
  • instead of `echo ${array1[@]} | tr ' ' '\n'`, use `printf "%s\n" "${array1[@]}"` -- the echo pipeline will give the wrong results if any array element contains spaces. – glenn jackman Jun 11 '13 at 01:25
  • Edited, thank you. The solution was targeting numbers specifically. – Sir Athos Jun 11 '13 at 15:55
0

Here's a solution with standard command line tools (sort and join):

join <(printf %s\\n "${array1[@]}" | sort -u) \
     <(printf %s\\n "${array2[@]}" | sort -u) | sort -n

join requires its inputs to be sorted, and does not recognize numerical sort order. Consequently, I sort both lists in the default collation order, join them, and then resort the result numerically.

I also assumed that you'd created the arrays really as arrays, i.e.:

array1=(20 30 40 50)

I think the rest is more or less self-evident, possibly with the help of help printf and man bash.

rici
  • 234,347
  • 28
  • 237
  • 341
0

maybe you can use perl for try.

#!/bin/perl
use warnings;
use strict;

my @array1 = (20,30,40,50);
my @array2 = (10,20,30,80,100,110,40);
my @array3 = ();
foreach my $x (@array1) {
    # body...
    if (grep(/$x/, @array2)){
        print "found $x\n";
        @array3=(@array3,$x);
    };
}
print @array3
Sylar
  • 1
  • 1
-1

Consider using python:

In [6]: array1 = (20,30,40,50)

In [7]: array2 = (10,20,30,80,100,110,40)

In [8]: set(array1) & set(array2)
Out[8]: set([40, 20, 30])
Fredrik Pihl
  • 44,604
  • 7
  • 83
  • 130