java中的组合向量产品库

时间:2015-06-07 10:08:57

标签: java

我正在寻找一个可以生成这样的矢量组合的Java库:

假设:

    <?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="#ffffff"
                android:endColor="#ffffff"
                android:angle="270" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="#ffffff"
                android:startColor="#ffffff"
                android:angle="270" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="#ffffff"
                android:startColor="#ffffff"
                android:angle="270" />
        </shape>
    </item>
</selector>

产生以下组合:

vector1 = {A, B, C}
vector2 = {0, 1, 2}

向量的数量给出了维度的数量(组合的列)。

在Python中,来自A, 0 A, 1 A, 2 B, 0 B, 1 B, 2 C, 0 C, 1 C, 2 库的函数product正是这样做的,但我还没有看到任何Java库。

感谢。

4 个答案:

答案 0 :(得分:1)

您可以使用java8流来完成它,就像从库中调用函数一样简单。假设你已经拥有:

List<String> vector1 = Arrays.asList("A","B","C");
List<Integer> vector2 = Arrays.asList(1,2,3);

您可以通过以下方式获得预期结果

Map<String, Integer> result = new HashMap<>();
vector1.stream().forEach(o1 -> vector2.stream().forEach(o2 -> result.put(o1,o2)));

或者,如果您更喜欢List of Tuples,那么您需要为对创建一个类,或者使用Tuple

答案 1 :(得分:1)

解决方案#1 :您可以使用地图将字符串与整数列表相关联。

public static void main(String[] args) {
    List<String> v1 = Arrays.asList("A", "B", "C");
    List<Integer> v2 = Arrays.asList(0, 1, 2);
    Map<String, List<Integer>> product = getProduct(v1, v2);
}

public static Map<String, List<Integer>> getProduct(List<String> v1, List<Integer> v2) {
    Map<String, List<Integer>> product = new HashMap<>();
    for (String e1 : v1) {
        product.put(e1, v2);
    }
    return product;
}

数据以这种方式表示:

First solution

解决方案#2 :您创建了Combination个对象的列表。

public class Combination<T1, T2> {

    protected final T1 value1;
    protected final T2 value2;

    public Combination(T1 value1, T2 value2) {
        this.value1 = value1;
        this.value2 = value2;
    }

    public T1 getValue1() {
        return value1;
    }

    public T2 getValue2() {
        return value2;
    }
}


public class CombinationGenerator<T1, T2> {

    protected final List<T1> values1;
    protected final List<T2> values2;

    public CombinationGenerator(List<T1> values1, List<T2> values2) {
        this.values1 = values1;
        this.values2 = values2;
    }

    public List<Combination<T1, T2>> getCombinations() {
        List<Combination<T1, T2>> combinations = new LinkedList<>();
        for (T1 e1 : values1) {
            for (T2 e2 : values2) {
                combinations.add(new Combination<>(e1, e2));
            }
        }
        return combinations;
    }
}


public static void main(String[] args) {
    List<String> v1 = Arrays.asList("A", "B", "C");
    List<Integer> v2 = Arrays.asList(0, 1, 2);

    CombinationGenerator<String, Integer> combGen = new CombinationGenerator<>(v1, v2);
    List<Combination<String, Integer>> combinations = combGen.getCombinations();
}

此解决方案返回9种组合的列表:

Solution #2

修改:对于解决方案#1,您可以使用GuavaMultimap

public static Multimap<String, Integer> getCombinations(List<String> v1, List<Integer> v2) {
    Multimap<String, Integer> combinations = ArrayListMultimap.create();
    for (String e1 : v1) {
        for (Integer e2 : v2) {
            combinations.put(e1, e2);
        }
    }
    return combinations;
}

答案 2 :(得分:0)

之前给出的答案很好但不适用于N维。

This代码是可推广的,也是正确的。

/*
 * www.javagl.de - Utilities - Combinatorics
 *
 * Copyright (c) 2008-2013 Marco Hutter - http://www.javagl.de
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package de.javagl.utils.math.combinatorics;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * A class providing an iterator over all combinations of a certain number
 * of elements, where the valid ranges may be different for each element
 * of the combination. For a set S = { S0, S1, ... Sn } there will be
 * |S0| * |S1| * ... * |Sn| possible combinations. Example:<br />
 * <pre>
 * S0 = {A,B,C}, |S0| = 3
 * S1 = {D,E}  , |S1| = 2
 * S2 = {A,E}  , |S2| = 2
 * S = { S0, S1, S2 }
 * m = |S0| * |S1| * |S0| = 3 * 2 * 2 = 12 combinations
 * 
 * Combinations:
 * [A, D, A]
 * [A, D, E]
 * [A, E, A]
 * [A, E, E]
 * [B, D, A]
 * [B, D, E]
 * [B, E, A]
 * [B, E, E]
 * [C, D, A]
 * [C, D, E]
 * [C, E, A]
 * [C, E, E]
 * </pre>
 *  
 * @param <T> The type of the elements
 */
public final class MixedRangeCombinationIterable<T> implements Iterable<List<T>>
{
    /**
     * The input elements
     */
    private List<? extends Collection<? extends T>> sets;

    /**
     * The total number of elements that the iterator will provide
     */
    private final int numElements;

    /**
     * Creates an iterable over all combinations of one element
     * of each of the given sets.
     *  
     * @param sets The input sets
     */
    public MixedRangeCombinationIterable(
        List<? extends Collection<? extends T>> sets)
    {
        this.sets = sets;
        int m = 0;
        if (sets.size() > 0)
        {
            m = 1;
        }
        for (Collection<? extends T> set : sets)
        {
            m *= set.size();
        }
        this.numElements = m;
    }

    @Override
    public Iterator<List<T>> iterator()
    {
        return new Iterator<List<T>>()
        {
            /**
             * The element counter
             */
            private int current = 0;

            /**
             * The current combination
             */
            private List<T> currentCombination = new ArrayList<T>();

            /**
             * The iterators over the individual sets
             */
            private List<Iterator<? extends T>> subIterators = 
                new ArrayList<Iterator<? extends T>>(
                    Collections.<Iterator<? extends T>>nCopies(
                        sets.size(), null));

            // Initialize the sub-iterators and the first combination
            {
                if (numElements > 0)
                {
                    for (int i=0; i<sets.size(); i++)
                    {
                        Iterator<? extends T> subIterator = 
                            sets.get(i).iterator();
                        subIterators.set(i, subIterator);
                        currentCombination.add(subIterator.next());
                    }
                }
            }

            @Override
            public boolean hasNext()
            {
                return current < numElements;
            }

            @Override
            public List<T> next()
            {
                if (!hasNext())
                {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(currentCombination);
                increase(sets.size()-1);
                current++;
                return result;
            }

            /**
             * Increases the selection of elements by one.
             * 
             * @param index The index to increase
             */
            private void increase(int index)
            {
                if (index < 0)
                {
                    return;
                }
                Iterator<? extends T> subIterator = subIterators.get(index);
                if (subIterator.hasNext())
                {
                    currentCombination.set(index, subIterator.next());
                }
                else
                {
                    subIterator = sets.get(index).iterator();
                    subIterators.set(index, subIterator);
                    currentCombination.set(index, subIterator.next());
                    increase(index-1);
                }

            }

            @Override
           public void remove()
            {
                throw new UnsupportedOperationException(
                    "May not remove elements from a combination");
            }
        };
    }
}

典型用法是:

List<List<Integer>> inputs = new ArrayList<List<Integer>>();
input.add(Arrays.asList(0, 1, 2));
input.add(Arrays.asList(0, 1, 2, 3));
input.add(Arrays.asList(0, 1));

MixedRangeCombinationIterable<Integer> product = 
    new MixedRangeCombinationIterable(inputs)

for(List<Integer> combination: product){
    System.out.println(combination)
}

答案 3 :(得分:0)

以下是计算这样的矢量积的类,也称为输入空间的Cartesian Product。它适用于任意数据类型和任意数量的维度。

(原来是I published it on GitHub,但现在它是在通常的stackoverflow许可下发布的)

它在构造函数中接收集合列表。这些集合中的每一个都提供了一个迭代器,用于迭代各自的维度。整个类本身实现为Iterable(基本上只包装相应的Iterator类)。在每个时间点,此迭代器仅维护集合的“当前”迭代器列表,并在调用next()时返回相应的元素并增加迭代器。

这种方法的优点是将整个笛卡尔积保存在内存中必要。可以迭代一个大于可用物理内存的笛卡尔积(考虑到笛卡尔积很大,这可能很重要)。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * A class providing an iterator over all combinations of a certain number
 * of elements, where the valid ranges may be different for each element
 * of the combination. For a set S = { S0, S1, ... Sn } there will be
 * |S0| * |S1| * ... * |Sn| possible combinations. Example:<br />
 * <pre>
 * S0 = {A,B,C}, |S0| = 3
 * S1 = {D,E}  , |S1| = 2
 * S2 = {A,E}  , |S2| = 2
 * S = { S0, S1, S2 }
 * m = |S0| * |S1| * |S0| = 3 * 2 * 2 = 12 combinations
 * 
 * Combinations:
 * [A, D, A]
 * [A, D, E]
 * [A, E, A]
 * [A, E, E]
 * [B, D, A]
 * [B, D, E]
 * [B, E, A]
 * [B, E, E]
 * [C, D, A]
 * [C, D, E]
 * [C, E, A]
 * [C, E, E]
 * </pre>
 *  
 * @param <T> The type of the elements
 */
public final class MixedRangeCombinationIterable<T> implements Iterable<List<T>>
{
    /**
     * The input elements
     */
    private List<? extends Collection<? extends T>> sets;

    /**
     * The total number of elements that the iterator will provide
     */
    private final int numElements;

    /**
     * Creates an iterable over all combinations of one element
     * of each of the given sets.
     *  
     * @param sets The input sets
     */
    public MixedRangeCombinationIterable(
        List<? extends Collection<? extends T>> sets)
    {
        this.sets = sets;
        int m = 0;
        if (sets.size() > 0)
        {
            m = 1;
        }
        for (Collection<? extends T> set : sets)
        {
            m *= set.size();
        }
        this.numElements = m;
    }

    @Override
    public Iterator<List<T>> iterator()
    {
        return new Iterator<List<T>>()
        {
            /**
             * The element counter
             */
            private int current = 0;

            /**
             * The current combination
             */
            private List<T> currentCombination = new ArrayList<T>();

            /**
             * The iterators over the individual sets
             */
            private List<Iterator<? extends T>> subIterators = 
                new ArrayList<Iterator<? extends T>>(
                    Collections.<Iterator<? extends T>>nCopies(
                        sets.size(), null));

            // Initialize the sub-iterators and the first combination
            {
                if (numElements > 0)
                {
                    for (int i=0; i<sets.size(); i++)
                    {
                        Iterator<? extends T> subIterator = 
                            sets.get(i).iterator();
                        subIterators.set(i, subIterator);
                        currentCombination.add(subIterator.next());
                    }
                }
            }

            @Override
            public boolean hasNext()
            {
                return current < numElements;
            }

            @Override
            public List<T> next()
            {
                if (!hasNext())
                {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(currentCombination);
                increase(sets.size()-1);
                current++;
                return result;
            }

            /**
             * Increases the selection of elements by one.
             * 
             * @param index The index to increase
             */
            private void increase(int index)
            {
                if (index < 0)
                {
                    return;
                }
                Iterator<? extends T> subIterator = subIterators.get(index);
                if (subIterator.hasNext())
                {
                    currentCombination.set(index, subIterator.next());
                }
                else
                {
                    subIterator = sets.get(index).iterator();
                    subIterators.set(index, subIterator);
                    currentCombination.set(index, subIterator.next());
                    increase(index-1);
                }

            }

            @Override
           public void remove()
            {
                throw new UnsupportedOperationException(
                    "May not remove elements from a combination");
            }
        };
    }
}

此类的用法可能如下所示:

List<List<Integer>> inputs = new ArrayList<List<Integer>>();
input.add(Arrays.asList(0, 1, 2));
input.add(Arrays.asList(0, 1, 2, 3));
input.add(Arrays.asList(0, 1));

MixedRangeCombinationIterable<Integer> product = 
    new MixedRangeCombinationIterable(inputs)

for(List<Integer> combination: product){
    System.out.println(combination)
}