1

I have a shell script in which I have defined an array. The array contains more than 2 elements. I need to find the combination of all the elements in my array. Suppose, if my array has the elements, {12345, 56789, 98765}, I am trying to get the output as,

12345, 56789
12345, 98765
56789, 98765

I tried the php code from here.

<?php
function pc_permute($items, $perms = array( )) {
    if (empty($items)) {
        print join(' ', $perms) . "\n";
    }  else {
        for ($i = count($items) - 1; $i >= 0; --$i) {
             $newitems = $items;
             $newperms = $perms;
             list($foo) = array_splice($newitems, $i, 1);
             array_unshift($newperms, $foo);
             pc_permute($newitems, $newperms);
         }
    }
}
pc_permute(split(' ', '12345 56789 98765'));
?>

I get the output as,

12345 56789 98765
56789 12345 98765
12345 98765 56789
98765 12345 56789
56789 98765 12345
98765 56789 12345

Is it possible to get the combination in 2 elements sized output? I am not concerned with the order and so if A B is got as a combination, I do not need the reverse (B A).

  • You seem to be looking for combinations not permutations if order is not material – iruvar Apr 8 '14 at 21:39
  • Yeah, I am looking for combinations. I always get confused between those 2 terms :) – Ramesh Apr 8 '14 at 21:40
1

All you need is printf. It's the print function - that's its job.

printf '%s\t%s\n' ${array[@]}

You do it like this:

( set -- 12345 56789 98765; for i ; do 
    eval set -- $(printf '"$%s" ' `seq 2 $#` 1)
    echo "$*"
done )

OUTPUT

56789 98765 12345
98765 12345 56789
12345 56789 98765

I didn't need eval - that was dumb. Here's a better one:

( set -- 12345 56789 98765 ; 
until [ $((i=i+1)) -gt $# ] ; do
    set -- $(s=$1 ; shift ; printf '%s\n' "$@" "$s")
    printf '%s ' "$@" ; echo
done)

OUTPUT

56789 98765 12345
98765 12345 56789
12345 56789 98765

And then if you want only two elements you just change it a little bit - one more line:

( set -- 12345 56789 98765 ;
    until [ $((i=i+1)) -ge $# ] ; do
        set -- $(s=$1 ; shift ; printf '%s\n' "$@" "$s")
        v="${v}$(printf '%s ' "$@")"
    done ; printf "%s\t%s\n" $v
    )

OUTPUT

56789   98765
12345   98765
12345   56789

I do this all of the time, but never the bashisms. I always work with the real shell array so it took a few minutes to get hold of it.

Here's a little script I wrote for another answer:

    abc="a b c d e f g h i j k l m n o p q r s t u v w x y z"
for l in $abc ; do { 
        h= c= ; [ $((i=i+1)) -gt 26 ] && n=$((n+26)) i=
    xyz=$(x=${xyz:-$abc} ;\
        printf %s\\n ${x#?} $l)
    mid=$(set -- $xyz ; eval echo \$$((${#}/4))) ;\
        echo "$mid $l" >&2 ;
        [ $(((i+n)%${mod=3})) -eq 0 ] && c="$mid" h="${xyz%"$mid"*}"
    line="$(printf '%s ' $h $c ${xyz#"$h"})"
    printf "%s$(printf %s ${xyz#?}${mid})\n" \
        ${line} >|/tmp/file$((i+n))
} ; done

This writes to 26 files. They look like this only they increment per file:

bcdefghijklmnopqrstuvwxyzag
ccdefghijklmnopqrstuvwxyzag
dcdefghijklmnopqrstuvwxyzag
ecdefghijklmnopqrstuvwxyzag
fcdefghijklmnopqrstuvwxyzag
gcdefghijklmnopqrstuvwxyzag
hcdefghijklmnopqrstuvwxyzag
icdefghijklmnopqrstuvwxyzag
jcdefghijklmnopqrstuvwxyzag
kcdefghijklmnopqrstuvwxyzag
lcdefghijklmnopqrstuvwxyzag
mcdefghijklmnopqrstuvwxyzag
ncdefghijklmnopqrstuvwxyzag
ocdefghijklmnopqrstuvwxyzag
pcdefghijklmnopqrstuvwxyzag
qcdefghijklmnopqrstuvwxyzag
rcdefghijklmnopqrstuvwxyzag
scdefghijklmnopqrstuvwxyzag
tcdefghijklmnopqrstuvwxyzag
ucdefghijklmnopqrstuvwxyzag
vcdefghijklmnopqrstuvwxyzag
wcdefghijklmnopqrstuvwxyzag
xcdefghijklmnopqrstuvwxyzag
ycdefghijklmnopqrstuvwxyzag
zcdefghijklmnopqrstuvwxyzag
acdefghijklmnopqrstuvwxyzag
  • I need all the combinations. with printf it is just splitting the input into 2 variables and printing. I tried the array array+=(s1 s2 s3 s4 s5 s6 s7). – Ramesh Apr 9 '14 at 1:32
  • Ok. So printf printf. – mikeserv Apr 9 '14 at 1:33
  • Nopes. It is not working. – Ramesh Apr 9 '14 at 1:37
  • @Ramesh - it does now, though at first I didn't understand what you were asking. It'll shuffle through all the args you care to give it. – mikeserv Apr 9 '14 at 2:14
  • thanks for the script in shell itself. I will take a look into it as soon as I get into server tomorrow. :) – Ramesh Apr 9 '14 at 2:53
1

I found out the way to print the elements in 2 element sized combinations. The php code is as below.

<?php
function pc_array_power_set($array) {
    // initialize by adding the empty set
    $results = array(array( ));

    foreach ($array as $element)
        foreach ($results as $combination)
            array_push($results, array_merge(array($element), $combination));
    return $results;
}
$set = array('12345', '56789', '98765');
$power_set = pc_array_power_set($set);
foreach (pc_array_power_set($set) as $combination) {
    if (2 == count($combination)) {
        print join("\t", $combination) . "\n";
    }
}
?>

The above code prints the output as,

56789   12345
98765   12345
98765   56789

Reference for the above code is here.

  • if you are going to use php you might as well use python: python -c 'from itertools import combinations;from sys import stdin; print list(combinations(stdin.readline().split(), 2))' <<<'12345 56789 98765' – iruvar Apr 8 '14 at 23:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.