6

使用 guava 12 Collections2.permutations(),我想知道是否可以限制排列的大小?

更准确地说,我想在 n 个元素的列表中获取 k 大小排列的列表,而不是获取所有 n 大小排列的列表。

目前,如果我传递 4 个水果的列表,permutations()当前将返回 24 个 4 大小排列的列表,尽管我只对检索 4 个唯一大小为 3 的排列感兴趣。

假设我有 4 种水果的清单:

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

如果我只对大小 3 的排列感兴趣,我希望返回以下内容:

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

任何人都可以提供任何解决方案的提示吗?谢谢 !

4

3 回答 3

9

这段代码计算出变化,然后在每个唯一的 3 组上运行排列。

即对于“A”、“B”、“C”、“D”,可能性是 [[A, B, C], [A, B, D], [A, C, D], [B, C, D]]。然后我们计算每个三人组(或n-some)的排列,并将可能性附加到一个列表中。

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

再进一步PermutationsOfN.permutations( List list, int size )返回:
[[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;
  }
}

特别提到meriton,他的回答帮助我解决了这个问题

于 2012-06-20T16:26:14.253 回答
7

尽管您可以提交功能请求,但没有内置的 Guava 功能可以做到这一点。

如果我正在编写一个实现,我认为最简单的方法是遍历组合(使用Gosper 的 hack),然后使用 Collections2.permutations 对这些组合进行排列。

或者,基于此 Python 代码,对正常排列生成算法进行一些小的修改就足够了。

于 2012-06-20T14:19:05.927 回答
1

您的问题的直接答案是:

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;
}

进而:

    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);
    }

但它只需要第一个而不是一个特别定义的集合,你最好听从路易斯的建议

于 2012-06-20T14:28:25.183 回答