Skip to content

Instantly share code, notes, and snippets.

@skchronicles
Last active October 22, 2024 16:19
Show Gist options
  • Save skchronicles/ec58f2b8d7af351ed59f354861768af5 to your computer and use it in GitHub Desktop.
Save skchronicles/ec58f2b8d7af351ed59f354861768af5 to your computer and use it in GitHub Desktop.
Unique possible combinations bash
#!/usr/bin/env bash
set -euo pipefail
function unique_combinations() {
# Returns all unique possible combinations
# of a collection of elements of a given length,
# to return all possible unique combinations,
# set the last argument equal to the length of
# the input collection, see example below:
# @Input $1 to (N-1): Set of items to permutate
# @Input $N: Cardinality of the unique combination sets
# @Example:
# $ unique_combinations A B C 3
# > A
# > B
# > C
# > A B
# > A C
# > B C
# > A B C
# Check if GNU parallel is installed
command -V parallel &> /dev/null || \
{ cat <<< 'Error: missing GNU parallel, exiting now!' 1>&2; return 1; }
# Get all the args except the last
items=("${@:1:$(($#-1))}")
# bash get length of an array
n="${@: -1}"
( for i in $(seq 1 $n); do
# Building GNU parallel
# commands to generate
# unique combinations
# of cardinality N
echo -ne "\nparallel --plus echo {choose_k}"
for j in $(seq 1 $i); do
echo -n " ::: ${items[@]}";
done
# Add a trailing newline
# char, remove empty line,
# exec the GNU parallel cmd
done; echo ) | awk 'NF' | bash
}
@skchronicles
Copy link
Author

skchronicles commented Oct 22, 2024

Python-based implementation

This python-based implementation is orders of magnitude (20-30x times) faster than the GNU parallel implementation above.

#!/usr/bin/env bash

set -euo pipefail

function unique_combinations() {
    # Returns all unique possible combinations
    # of a collection of elements of a given length, 
    # to return all possible unique combinations, 
    # set the last argument equal to the length of 
    # the input collection, see example below: 
    # @Input $1 to (N-1): Set of items to permutate
    # @Input $N: Cardinality of the unique combination sets, can include a range or a set number
    # @Example: 
    # $ unique_combinations A B C 2-3
    # > A B
    # > A C
    # > B C
    # > A B C
    # Check if python is installed
    command -V python &> /dev/null || \
        { cat <<< 'Error: missing python, exiting now!' 1>&2; return 1; }
        
cat << EOF | python /dev/stdin "$@"
from __future__ import print_function
import sys

def unique_n_len_combinations(items, n):
    if n==0: yield []
    else:
      for i in range(len(items)):
            for cc in unique_n_len_combinations(items[i+1:], n-1):
                yield [str(items[i])] + cc

# Parse command line arguments
s = sys.argv[1:-1]
n = sys.argv[-1]
range_len = len([ _ for _ in n.split('-') if _ ])
# Check if range is specified
start = 0 if '-' not in n else int(n.split('-')[0])-1
stop = int(n) if '-' not in n \
else len(s) if range_len==1 else int(n.split('-')[1])
# Generate unique combinations
# differing set lengths
for i in range(start,stop):
    for comb in unique_n_len_combinations(s, i+1):
        print(' '.join(comb))
EOF
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment