使用自定义密钥进行Java 8分组

时间:2015-08-28 13:55:37

标签: java java-8 java-stream collectors

我有一系列输入字符串,格式如下:

typeA:code1,
typeA:code2,
typeA:code3,
typeB:code4,
typeB:code5,
typeB:code6,
typeC:code7,
...

我需要获得具有以下结构的Map<String, List<String>>

typeA, [code1, code2, code3]
typeB, [code4, code5, code6]
typeC, [code7, code8, ...]

要抓住的是生成我需要在每个输入字符串上调用类似函数的每个类型:

public static String getType(String code)
{
  return code.split(":")[0];  // yes this is horrible code, it's just for the example, honestly
}

我非常有信心Streams and Collectors可以做到这一点,但我正在努力获得正确的法术咒语来实现它。

4 个答案:

答案 0 :(得分:8)

这是一种方法(假设该类名为A):

Map<String, List<String>> result = Stream.of(input)
                          .collect(groupingBy(A::getType, mapping(A::getValue, toList())));

如果要对输出进行排序,可以使用TreeMap而不是默认的HashMap:

.collect(groupingBy(A::getType, TreeMap::new, mapping(A::getValue, toList())));

完整示例:

public static void main(String[] args) {
  String input[] = ("typeA:code1," +
                "typeA:code2," +
                "typeA:code3," +
                "typeB:code4," +
                "typeB:code5," +
                "typeB:code6," +
                "typeC:code7").split(",");

  Map<String, List<String>> result = Stream.of(input)
                    .collect(groupingBy(A::getType, mapping(A::getValue, toList())));
  System.out.println(result);
}

public static String getType(String code) {
  return code.split(":")[0];
}
public static String getValue(String code) {
  return code.split(":")[1];
}

答案 1 :(得分:6)

如果考虑省略的内容,代码变得简单,你也需要分割字符串的第二部分:

Map<String, List<String>> result = Stream.of(input).map(s->s.split(":", 2))
    .collect(groupingBy(a->a[0], mapping(a->a[1], toList())));

(假设您有import static java.util.stream.Collectors.*;

String拆分为数组没有任何问题,对于您使用单个简单字符而不是复杂正则表达式进行拆分的常见情况,该实现甚至具有“快速路径”。

答案 2 :(得分:2)

虽然我太慢了,但这里有一个MCVE,显示了Collectors#groupingBy如何解决这个问题。

显然有不同的选项来定义&#34;分类器&#34;和#34; mapper&#34;。在这里,我只是使用String#substring来查找":"之前和之后的部分。

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class GroupingBySubstringsTest
{
    public static void main(String[] args)
    {
        List<String> strings = new ArrayList<String>();
        strings.add("typeA:code1");
        strings.add("typeA:code2");
        strings.add("typeA:code3");
        strings.add("typeB:code4");
        strings.add("typeB:code5");
        strings.add("typeB:code6");
        strings.add("typeC:code7");

        Map<String, List<String>> result = strings.stream().collect(
            groupingBy(s -> s.substring(0, s.indexOf(":")), 
                mapping(s -> s.substring(s.indexOf(":")+1), toList())));

        for (Entry<String, List<String>> entry : result.entrySet())
        {
            System.out.println(entry);
        }
    }
}

答案 3 :(得分:0)

考虑学生课堂:

public Student(String name, Address add) {
    super();
    this.name = name;
    this.add = add;
}
private String name;
private Address add;
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Address getAdd() {
    return add;
}
public void setAdd(Address add) {
    this.add = add;
}

}

和地址类:

class Address{

public Address(String city, String state) {
    super();
    this.city = city;
    State = state;
}
private String city;
private String State;
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getState() {
    return State;
}
public void setState(String state) {
    State = state;
}

}

现在,如果我想根据属于地址类的城市和州来对学生进行分组:

Student s1 = new Student("Rohit", new Address("Mumbai", "MH"));
    Student s2 = new Student("Sudeep", new Address("Mumbai", "MH"));
    Student s3 = new Student("Amit", new Address("Pune", "MH"));
    Student s4 = new Student("Rahul", new Address("Blore", "KR"));
    Student s5 = new Student("Vishal", new Address("Blore", "KR"));
    
    List<Student> st =  Arrays.asList(s1,s2,s3,s4,s5);
    
    Function<Student, String> compositeKey = studRecord -> studRecord.getAdd().getCity()+":"+ studRecord.getAdd().getState();
    
    Map<String, List<Student>> groupedStudent =  st.stream()
            .collect(Collectors.groupingBy(compositeKey));