如何将一个列表分成一个较小的列表

时间:2017-11-21 12:45:35

标签: java optimization lambda

我目前正在开展一个项目,我有以下内容

    for (String x : listOne) {
        for (String y : listOne) {
            for (String z : listTwo) {
                if (x.noun1.equal(z.noun1) && y.noun2.equals(z.noun2)) {
                    doSomething();
                }
            }
        }
    }

其中listOne和listTwo只是ArrayList<String> s。两个ArrayList都持有动词:名词:名词对,其中我们在索引0处有一个动词,在索引1处有一个名词,在索引2处有一个名词(依此类推)。

这基本上只是一种强力搜索算法。 为了优化搜索过程,我想创建一个较小的三元组列表,它具有与z相同的名词1和一个较小的三元组列表,它们具有相同的名词2 ž。我对Java中的lambda表达式一无所知,但经过一些研究,我确信在java中使用lambdas可以做到这一点。

关于我如何进行此操作的任何帮助,或任何可能有用的文章将不胜感激。

编辑:这是一个例子

ArrayList<String> al1 = "IsA","Car","Vehicle","IsA","house","building"..
ArrayList<String> al2 = "IsA","house","home"..

由于索引4处的al1名词1等于索引1处的al2 s名词1.我们返回一个包含&#34; IsA&#34;的新ArrayList或Map, &#34;房子&#34;&#34;建筑&#34;

3 个答案:

答案 0 :(得分:1)

你应该把你以前的问题联系起来,否则你很难理解你想要的东西。 IIUYC你要求将三色列表转换为三元组列表。这很简单:

@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
public static class Triplet {
    public static List<Triplet> listFrom(List<String> strings) {
        Preconditions.checkArgument(strings.size() % 3 == 0);
        final List<Triplet> result = new ArrayList<>();
        for (int i=0; i<strings.size(); i+=3) {
            result.add(new Triplet(
                    strings.get(i), strings.get(i+1), strings.get(i+2)));
        }
        return result;
    }

    public final String verb;
    public final String noun1;
    public final String noun2;
}

以上注释来自project lombok并完全按照他们的说法行事。如果您不想使用Lombok,请手动编写需要的内容。

这实际上是全部,但我会扩展上一个问题。上面没有使用lambdas,现在你得到两个。

您准备数据

final List<Triplet> tripletsOne = Triplet.listFrom(listOne);
final List<Triplet> tripletsTwo = Triplet.listFrom(listTwo);
final Map<String, List<Triplet>> mapOneByNoun1 = tripletsOne.stream()
        .collect(Collectors.groupingBy(t -> t.noun1));
final Map<Object, List<Triplet>> mapOneByNoun2 = tripletsOne.stream()
        .collect(Collectors.groupingBy(t -> t.noun2));
final List<Triplet> EMPTY = Collections.emptyList();

由于Collectors.groupingBy,这比我之前的方法更简单。

在两种情况下都发生z,在最外层的循环中使用它是有意义的

for (final Triplet z : tripletsTwo) {
    for (final Triplet x : mapOneByNoun1.getOrDefault(z.noun1, EMPTY)) {
        for (final Triplet y : mapOneByNoun2.getOrDefault(z.noun2, EMPTY)) {
            doSomething(x, y);
        }
    }
}

就是这样。

答案 1 :(得分:0)

不确定你为什么要找lambda?请提供方案..

如果您的输入是具有快速随机访问权限的列表,则可以使用索引流来解决您的问题:

public static List<String> f(int n, List<String> input) {
int fence = IntStream.range(0, input.size())
                     .filter(idx -> input.get(idx).equals("B")) // leave only B's
                     .skip(n-1)
                     .findFirst() // an index of n-th B
                     .getAsInt(); // with throw NoSuchElementException if not enough B's
return input.subList(0, fence+1);
}

答案 2 :(得分:0)

我想您想了解如何构建for循环?

写了一个简单的for来理解你的预期结果。这是你想要达到的目标吗?

    // Considering we have these lists.. 
    // ArrayList<String> al1 = "IsA","Car","Vehicle","IsA","house","building"..
    // ArrayList<String> al2 = "IsA","house","home"..

    List<String> result = new ArrayList<>();
    for(int i=0; i<al1.size(); i+=3) {
        for(int j=0; j<al2.size(); j+=3) {
            if(i+2 < al1.size() && j+2 < al2.size()) {
                if (al1.get(i).equals(al2.get(i)) && al1.get(i+1).equals(al2.get(i+1))) {
                    result.add(al1.get(i));
                    result.add(al1.get(i+1));
                    result.add(al1.get(i+2));
                }
            }
        }
    }

对于第二次检查,我:e。要检查名词2,可以更新条件以添加名词2的新检查 -

if (
(al1.get(i).equals(al2.get(i)) && al1.get(i+1).equals(al2.get(i+1))) ||
(al1.get(i).equals(al2.get(i)) && al1.get(i+2).equals(al2.get(i+2)))
) { .. }