Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava Collections : limit permutation size

Using guava 12 Collections2.permutations(), I'm wondering if it's possible to limit the size of the permutations ?

More precisely, I would like to get a list of k-sized permutations within a list of n elements, instead of getting a list of all n-sized permutations.

Currently, if I pass a list of 4 fruits, permutations() will currently return a list of 24 4-sized permutations although I'm only interested in retrieving, say, the 4 unique size 3 permutations.

Say I have a list of 4 fruits :

["Banana", "Apple", "Orange", "Peach"]

If I'm only interested in size 3 permutations, I'd like the following returned :

["Banana", "Apple", "Orange"]
["Banana", "Apple", "Peach"]
["Banana", "Orange", "Peach"]
["Apple", "Orange", "Peach"]

Could anyone please provide any hints to a solution ? Thanks !

like image 911
jbmusso Avatar asked Jun 20 '12 13:06

jbmusso


3 Answers

This code works out the variations, then runs the permutations on each unique set of 3.

i.e. for "A", "B", "C", "D" the possibilities are [[A, B, C], [A, B, D], [A, C, D], [B, C, D]]. We then calculate the permutations on each threesome (or n-some) and append the possibilities to a list.

PermutationsOfN.processSubsets( List set, int k ) returns: [[A, B, C], [A, B, D], [A, C, D], [B, C, D]]

Taking it a bit further PermutationsOfN.permutations( List list, int size ) returns:
[[A, B, C], [A, C, B], [C, A, B], [C, B, A], [B, C, A], [B, A, C], [A, B, D], [A, D, B], [D, A, B], [D, B, A], [B, D, A], [B, A, D], [A, C, D], [A, D, C], [D, A, C], [D, C, A], [C, D, A], [C, A, D], [B, C, D], [B, D, C], [D, B, C], [D, C, B], [C, D, B], [C, B, D]]

import java.util.Collection;
import java.util.List;

import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

public class PermutationsOfN<T> {
  public static void main( String[] args ) {
    List<String> f = Lists.newArrayList( "A", "B", "C", "D" );
    PermutationsOfN<String> g = new PermutationsOfN<String>();
    System.out.println( String.format( "n=1 subsets %s", g.processSubsets( f, 1 ) ) );
    System.out.println( String.format( "n=1 permutations %s", g.permutations( f, 1 ) ) );
    System.out.println( String.format( "n=2 subsets %s", g.processSubsets( f, 2 ) ) );
    System.out.println( String.format( "n=2 permutations %s", g.permutations( f, 2 ) ) );
    System.out.println( String.format( "n=3 subsets %s", g.processSubsets( f, 3 ) ) );
    System.out.println( String.format( "n=3 permutations %s", g.permutations( f, 3 ) ) );
    System.out.println( String.format( "n=4 subsets %s", g.processSubsets( f, 4 ) ) );
    System.out.println( String.format( "n=4 permutations %s", g.permutations( f, 4 ) ) );
    System.out.println( String.format( "n=5 subsets %s", g.processSubsets( f, 5 ) ) );
    System.out.println( String.format( "n=5 permutations %s", g.permutations( f, 5 ) ) );
  }

  public List<List<T>> processSubsets( List<T> set, int k ) {
    if ( k > set.size() ) {
      k = set.size();
    }
    List<List<T>> result = Lists.newArrayList();
    List<T> subset = Lists.newArrayListWithCapacity( k );
    for ( int i = 0; i < k; i++ ) {
      subset.add( null );
    }
    return processLargerSubsets( result, set, subset, 0, 0 );
  }

  private List<List<T>> processLargerSubsets( List<List<T>> result, List<T> set, List<T> subset, int subsetSize, int nextIndex ) {
    if ( subsetSize == subset.size() ) {
      result.add( ImmutableList.copyOf( subset ) );
    } else {
      for ( int j = nextIndex; j < set.size(); j++ ) {
        subset.set( subsetSize, set.get( j ) );
        processLargerSubsets( result, set, subset, subsetSize + 1, j + 1 );
      }
    }
    return result;
  }

  public Collection<List<T>> permutations( List<T> list, int size ) {
    Collection<List<T>> all = Lists.newArrayList();
    if ( list.size() < size ) {
      size = list.size();
    }
    if ( list.size() == size ) {
      all.addAll( Collections2.permutations( list ) );
    } else {
      for ( List<T> p : processSubsets( list, size ) ) {
        all.addAll( Collections2.permutations( p ) );
      }
    }
    return all;
  }
}

A special mention goes to meriton whose answer here helped me work it out.

like image 109
mrswadge Avatar answered Nov 09 '22 21:11

mrswadge


There's no built-in Guava feature that does this, though you could submit a feature request.

If I were writing an implementation, I think the simplest way would be to iterate through combinations (with Gosper's hack), and then permutations of those with Collections2.permutations.

Alternately, it looks like some minor modifications to the normal permutation generation algorithm suffice, based on this Python code.

like image 20
Louis Wasserman Avatar answered Nov 09 '22 19:11

Louis Wasserman


A direct answer to your question would be this:

public static <X> List<List<X>> test(List<X> input, final int n, final int m) {
    int x = 0;

    List<List<X>> newPerm = Lists.newArrayList();
    Collection<List<X>> perm = Collections2.permutations(input);
    for (Iterator<List<X>> it = perm.iterator(); it.hasNext(); x++) {
        if (x >= n) {
            break;
        }

        List<X> list = it.next();
        newPerm.add(Lists.partition(list, m).get(0));
    }

    return newPerm;
}

and then:

    List<String> list = Lists.newArrayList("Banana", "Apple", "Orange", "Peach");
    List<List<String>> answer = test(list, 4, 3);
    for (List<String> list1 : answer) {
        System.out.println(list1);
    }

But it takes only the first ones and not a specifically defined set, your probably better off following Louis's advice

like image 1
epoch Avatar answered Nov 09 '22 21:11

epoch