aatuc210
aatuc210

Reputation: 1868

Streaming question: Best way to get property out of a List of Lists

I have created a list of say, 100 configurations. I have partitioned that list into groups of 10, so now I have List<List<Config>>. All of these configs have a common attribute value, the domainCode. What's the best way for me to get to that attribute? Say the config domain class looks like this:

public class Config {

    private String configId;
    private String portfolioId;
    private String domainCode;

    public Config(String configId, String portfolioId, String domainCode) {
        this.configId = configId;
        this.portfolioId = portfolioId;
        this.domainCode = domainCode;
    }

    public String getConfigId() { return configId;}
    public String getPortfolioSymbolCode() { return portfolioId;}
    public String getDomainCode() { return domainCode; }
}

I build 100 of them, then group them:

List<Config> configs = getAllConfigs();
List<List<Config>> partitionedConfigs = new ArrayList<>();
if (configs != null) {
    AtomicInteger counter = new AtomicInteger();
    partitionedConfigs.addAll(configs.stream()
            .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / 10))
            .values());
}

I pass partitionedConfigs to a method. That method needs domainCode. What's an efficient way to get the single domainCode out of partitionedConfigs? Even if there are 100 Config objects, the domain code is unique, there will only be one domain code. That is the one that my method needs to find.

Upvotes: 1

Views: 82

Answers (2)

Anonymous
Anonymous

Reputation: 86324

If you know that the domain code is unique across your Config objects, you should still check this assumption.

    List<List<Config>> partitionedConfigs = // get from somewhere;

    Set<String> uniqueDomainCode = partitionedConfigs.stream()
            .flatMap(List::stream)
            .map(Config::getDomainCode)
            .collect(Collectors.toSet());
    if (uniqueDomainCode.size() == 1) { // as expected
        String domainCode = uniqueDomainCode.iterator().next();
        // Do something with domain code
    } else {
        throw new IllegalStateException("Found " + uniqueDomainCode.size() + " domain codes, require 1");
    }

When we’re collecting into a Set, duplicate domain codes will be dropped, so we should end up with a set of size 1. Under two circumstances this will go wrong:

  1. If the original list of lists is empty (either the outer list is empty or all the inner lists are), the size of the set will be 0.
  2. If there were more than one domain code in the original list of lists, the size will be strictly greater than 1.

In both of these cases we will want to know that something has gone wrong. An exception is a typical way of signaling that, there are other ways.

PS If you love streams so much you don’t want to work with anything else, here’s a possibility:

    String firstDomainCode = partitionedConfigs.stream()
            .flatMap(List::stream)
            .map(Config::getDomainCode)
            .findAny()
            .orElseThrow( () -> new IllegalStateException("Empty list, so no domain code found"));
    boolean domainCodeIsUnique = partitionedConfigs.stream()
            .flatMap(List::stream)
            .map(Config::getDomainCode)
            .allMatch(firstDomainCode::equals);
    if (domainCodeIsUnique) {
        // Do something with firstDomainCode
    } else {
        throw new IllegalStateException("Domain code is not unique, it is required to be");
    }

Upvotes: 0

Ryuzaki L
Ryuzaki L

Reputation: 40078

you can get it from configs list it self

List<String> domains = configs.stream()
                              .map(Config::getDomainCode)
                              .collect(Collectors.toList());

Or from partitionedConfigs list also

 List<String> domains = partitionedConfigs.stream()
                                          .flatMap(List::stream)
                                          .map(Config::getDomainCode)
                                          .collect(Collectors.toList());

If every object in list has same domain name then you can get using findFirst

String domain = configs.stream()
                       .findFirst()
                       .map(Config::getDomainCode)
                       .orElse(null); // if list is empty give some default value

From partitionedConfigs list

String domain = partitionedConfigs.stream()
                                  .flatMap(List::stream)
                                  .findFirst()
                                  .map(Config::getDomainCode)
                                  .orElse(null); // if list is empty give some 

Upvotes: 2

Related Questions