繁体   English   中英

从多个 Set 值生成字符串排列(Java 8 Streams)

[英]Generate String Permutations from multiple Set values (Java 8 Streams)

我有两个集合 - 国家和州。 我想从两者中创建所有可能的排列。

import java.util.*;
import java.util.stream.Collectors;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World");

    Set<String> countryPermutations = new HashSet<>(
        Arrays.asList("United States of america", "USA"));
    Set<String> statePermutations = new HashSet<>(
        Arrays.asList("Texas", "TX"));

    Set<String> stateCountryPermutations = countryPermutations.stream()
        .flatMap(country -> statePermutations.stream()
            .flatMap(state -> Stream.of(state + country, country + state)))
        .collect(Collectors.toSet());

    Set<String> finalAliases = Optional.ofNullable(stateCountryPermutations)
        .map(Collection::stream).orElse(Stream.empty())
        .map(sc -> "houston " + sc)
        .collect(Collectors.toSet());
    System.out.println(stateCountryPermutationAliases);
  }
}

州或国家或两者的排列可以为空。 我仍然希望我的代码能够正常运行。

要求

  1. 如果状态排列为空,则最终输出应为 [Houston USA, Houston United States of America]

  2. 如果国家/地区排列为空,则最终输出应为 [Houston TX, Houston Texas]

  3. 如果两者都为空,则没有输出

我已将代码更改为以下

Set<String> stateCountryPermutations =
    Optional.ofNullable(countryPermutations)
        .map(Collection::stream)
        .orElse(Stream.empty())
        .flatMap(country -> Optional.ofNullable(statePermutations)
            .map(Collection::stream)
            .orElse(Stream.empty())
            .flatMap(state -> Stream.of(state + country, country + state)))
        .collect(Collectors.toSet());

这满足3。当任一排列为空时,不满足1 & 2。 我没有收到别名作为​​响应。 如何修改我的代码?

以下代码从任意数量的输入集创建所有组合,忽略空/空集:

Stream<Collection<String>> inputs = Stream.of(
        Arrays.asList("United States of america", "USA"),
        Arrays.asList("Texas", "TX"),
        Arrays.asList("Hello", "World"),
        null,
        new ArrayList<>());

Stream<Collection<List<String>>> listified = inputs
        .filter(Objects::nonNull)
        .filter(input -> !input.isEmpty())
        .map(l -> l.stream()
                .map(o -> new ArrayList<>(Arrays.asList(o)))
                .collect(Collectors.toList()));

Collection<List<String>> combinations = listified
        .reduce((input1, input2) -> {
            Collection<List<String>> merged = new ArrayList<>();
            input1.forEach(permutation1 -> input2.forEach(permutation2 -> {
                List<String> combination = new ArrayList<>();
                combination.addAll(permutation1);
                combination.addAll(permutation2);
                merged.add(combination);
            }));
            return merged;
        }).orElse(new HashSet<>());

combinations.forEach(System.out::println);

输出:

[United States of america, Texas, Hello]
[United States of america, Texas, World]
[United States of america, TX, Hello]
[United States of america, TX, World]
[USA, Texas, Hello]
[USA, Texas, World]
[USA, TX, Hello]
[USA, TX, World]

现在您可以使用您提到的辅助方法来创建每个组合的排列。 这个问题展示了如何生成一个列表的所有排列。

要重新表述您的问题,据我了解,你有几个收藏,让我们称他们的标签,并为所有非的置换null的集合,产生一个空流,如果一切都是null

这可以通过一个简单的逻辑来完成,流过所有集合,过滤掉null元素,将它们映射到Stream并使用streamA.stream().flatMap(… -> streamB.map(combiner))将它们减少到单个流streamA.stream().flatMap(… -> streamB.map(combiner))逻辑,但不能多次使用流。 为了解决这个问题,我们可以通过对流的供应商应用相同的逻辑来实现它。 另一个细节是.map(combiner)应该是a -> streamB.flatMap(b -> Stream.of(combine a and b, combine b and a))在你的情况下。

Stream.of(stateLabels, countryLabels) // stream over all collections
      .filter(Objects::nonNull)       // ignore all null elements
      .<Supplier<Stream<String>>>map(c -> c::stream) // map to a supplier of stream
      .reduce((s1,s2) -> // combine them using flatMap and creating a×b and b×a
          () -> s1.get().flatMap(x -> s2.get().flatMap(y -> Stream.of(x+" "+y, y+" "+x))))
      .orElse(Stream::empty) // use supplier of empty stream when all null
      .get() // get the resulting stream
      .map("houston "::concat) // combine all elements with "houston "
      .forEach(System.out::println);

使用测试用例进行演示:

// testcases
List<Collection<String>> countryLabelTestCases = Arrays.asList(
    Arrays.asList("United States of america", "USA"),
    null
);
List<Collection<String>> stateLabelTestCases = Arrays.asList(
    Arrays.asList("Texas", "TX"),
    null
);
for(Collection<String> countryLabels: countryLabelTestCases) {
    for(Collection<String> stateLabels: stateLabelTestCases) {
        // begin test case
        System.out.println(" *** "+(
            countryLabels==null? stateLabels==null? "both null": "countryLabels null":
                                 stateLabels==null? "stateLabels null": "neither null"
            )+":"
        );

        // actual operation:

        Stream.of(stateLabels, countryLabels)
              .filter(Objects::nonNull)
              .<Supplier<Stream<String>>>map(c -> c::stream)
              .reduce((s1,s2) -> () -> s1.get().flatMap(x ->
                                       s2.get().flatMap(y -> Stream.of(x+" "+y, y+" "+x))))
              .orElse(Stream::empty)
              .get()
              .map("houston "::concat)
              .forEach(System.out::println);

        // end of operation
        System.out.println();
    }
}
 *** neither null:
houston Texas United States of america
houston United States of america Texas
houston Texas USA
houston USA Texas
houston TX United States of america
houston United States of america TX
houston TX USA
houston USA TX

 *** stateLabels null:
houston United States of america
houston USA

 *** countryLabels null:
houston Texas
houston TX

 *** both null:

如果您想以列表而不是字符串的形式获取排列,请创建此辅助方法

static <T> List<T> merge(List<T> a, List<T> b) {
    return Stream.concat(a.stream(), b.stream()).collect(Collectors.toList());
}

并将流操作更改为

Stream.of(stateLabels, countryLabels)
      .filter(Objects::nonNull)
      .<Supplier<Stream<List<String>>>>map(c ->
          () -> c.stream().map(Collections::singletonList))
      .reduce((s1,s2) -> () -> s1.get().flatMap(x ->
                               s2.get().flatMap(y -> Stream.of(merge(x,y), merge(y,x)))))
      .orElse(Stream::empty)
      .get()
      .map(list -> merge(Collections.singletonList("houston"), list))
      // proceed processing the List<String>s

请注意,要支持两个以上的集合,您只需更改Stream.of(stateLabels, countryLabels) ,插入其他集合。

如果要创建这样的数据:

[text1=text2, text1=text3, text2=text3]

在这里你可以怎么做:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class MainTest {

    public static void main(String[] args) {
        processData();
    }

    public static void processData() {
        List<String> datalist = new ArrayList<>();
        datalist.add("text1");
        datalist.add("text2");
        datalist.add("text3");
        List<String> tempList = new ArrayList<>(datalist);
        List<String> result = datalist.stream()
                    .flatMap(str1 -> getList(tempList, str1).stream().map(str2 -> str1 + "=" +str2))
                    .collect(Collectors.toList());
        System.out.println(result);
    }

    private static List<String> getList(List<String> list, String obj){
        list.remove(obj);
        return list;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM