如何使特定条件下的聚合java8

时间:2018-07-10 13:02:08

标签: java java-8

我想汇总以下示例:

我有一个List<CsvEntity> toSort =的实体,如下所述:

toSort.add(new CsvEntity(...))..

public class CsvEntity {
    String OCCURRENCES, STATUS, MESSAGE, STACK_TRACE;
}

数据:

  OCCURRENCES,   STATUS,MESSAGE,STACK_TRACE   
    1,       FAIL, MESSAGE1, STACK1
    1,       PASS, MESSAGE1, STACK1
    1,       FAIL, MESSAGE1, STACK1
    1,       FAIL, MESSAGE2, STACK2 => aggregate MESSAGE & STACK_TRACE)
    1,       PASS, MESSAGE2, STACK2
    1,       PASS, MESSAGE3, STACK3
    1,       PASS, MESSAGE3, STACK3

结果应为(作为数据结构):

OCCURRENCES,STATUS,MESSAGE,STACK_TRACE
3, FAIL, MESSAGE1, STACK1
2, FAIL, MESSAGE2, STACK2
2, PASS, MESSAGE3, STACK3

我尝试使用:

Map<String, Integer> group = toSort.stream().collect(
    Collectors.groupingBy(
        CsvEntity::getSTACK_TRACE, 
        Collectors.groupingBy(CsvEntity::getMESSAGE),
        Collectors.summingInt(s -> Integer.parseInt(s.getOCCURRENCES()))
    )
);

但是该组仅返回STACK_TRACE,而不返回整个CsvEntity ...

是否可以更改代码中的内容?

3 个答案:

答案 0 :(得分:2)

除了我的其他答案外,您还可以使用equals收集器,但首先要在hashcode类中覆盖CsvEntity / class CsvEntity { private String OCCURRENCES,STATUS,MESSAGE,STACK_TRACE; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CsvEntity csvEntity = (CsvEntity) o; return Objects.equals(MESSAGE, csvEntity.MESSAGE) && Objects.equals(STACK_TRACE, csvEntity.STACK_TRACE); } @Override public int hashCode() { return Objects.hash(MESSAGE, STACK_TRACE); } public CsvEntity(String OCCURRENCES, String STATUS, String MESSAGE, String STACK_TRACE) { ... } ... ... ... } ,如下所示:

 List<CsvEntity> resultSet
                = source.stream()
                .collect(Collectors.groupingBy(Function.identity(),
                        LinkedHashMap::new,
                        Collectors.summingInt(e -> Integer.parseInt(e.getOCCURRENCES()))))
                .entrySet()
                .stream()
                .map(x -> {
                    CsvEntity c = x.getKey();
                    return new CsvEntity(Integer.toString(x.getValue()),
                          c.getSTATUS(), c.getMESSAGE(), c.getSTACK_TRACE());
                }).collect(Collectors.toList());

然后是流管道:

[CsvEntity{OCCURRENCES='3', STATUS='FAIL', MESSAGE='MESSAGE1', STACK_TRACE='STACK1'}, 
 CsvEntity{OCCURRENCES='2', STATUS='FAIL', MESSAGE='MESSAGE2', STACK_TRACE='STACK2'}, 
 CsvEntity{OCCURRENCES='2', STATUS='PASS', MESSAGE='MESSAGE3', STACK_TRACE='STACK3'}]

这再次产生以下结果:

var uuid = require('uuid-v4');
// Generate a new UUID
var myUUID = uuid();
// Validate a UUID as proper V4 format
uuid.isUUID(myUUID);  // true

var questionNum = 0;

class App extends Component {

  constructor(props){
    super(props);
      this.state = {
        key: uuid(),
        title: "",
        author: "",
        questions: [],
        answers: []
      }

      this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;

    this.setState({
        [name]: value
    });
  }

  addQuestion = () => {
    questionNum++;
    this.setState({
      questions: this.state.questions.concat(["question","hi"])
    });
    console.log(this.state.questions);
    this.setState({
      answers: this.state.answers.concat(["hello","hi"])
    });
    console.log(this.state.answers);
    console.log(questionNum);
    console.log(this.state.title);
    console.log(this.state.author);
  }

  render() {
    return (
      <div className="App">

        <div>
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <h1 className="App-title">Quiz Form 2.0</h1>
          </header>
          <p className="App-intro">
            To get started, edit <code>src/App.js</code> and save to reload.
          </p>
          </div>

        <div>
          <form>
            <div className="Intro">
              Give your Quiz a title: <input type="text" value={this.state.title} onChange={this.handleChange} name="title" key={uuid()}/><br/>
              Who's the Author? <input type="text" value={this.state.author} onChange={this.handleChange} name="author" key={uuid()}/><br/><br/>
            </div>
            <div className="questions">
              Now let's add some questions... <br/>
              {this.addQuestion}
            </div>
          </form>
          <button onClick={this.addQuestion}>Add Question</button>
        </div>

      </div>
    );
  }
}

export default App;

答案 1 :(得分:0)

以下是如何分组和汇总数据的示例。希望这可以帮助。

代码

 public static void main(String[] args) {
        List<CsvEntity> toSort = getToSort();

        Map<String, List<CsvEntity>> grouped = toSort.stream()
                .collect(Collectors.groupingBy(o -> o.stackTrace));

        List<CsvEntity> aggregated = grouped.entrySet()
                .stream()
                .map(entry -> {
                    CsvEntity csvEntity = entry.getValue().get(0);
                    String occurrences = String.valueOf(entry.getValue().size());

                    return new CsvEntity(occurrences, csvEntity.status, csvEntity.message, csvEntity.stackTrace);
                })
                .collect(Collectors.toList());

        aggregated.forEach(csvEntity -> System.out.println(csvEntity.toString()));
    }

    private static List<CsvEntity> getToSort() {
        return Arrays.asList(
                new CsvEntity("1", "Fail", "Message 1", "Stack 1"),
                new CsvEntity("1", "Pass", "Message 1", "Stack 1"),
                new CsvEntity("1", "Fail", "Message 1", "Stack 1"),
                new CsvEntity("1", "Fail", "Message 2", "Stack 2"),
                new CsvEntity("1", "Pass", "Message 2", "Stack 2"),
                new CsvEntity("1", "Pass", "Message 3", "Stack 3"),
                new CsvEntity("1", "Pass", "Message 3", "Stack 3")
        );
    }

    public static class CsvEntity {
        String occurrences;
        String status;
        String message;
        String stackTrace;

        CsvEntity(String occurrences, String status, String message, String stackTrace) {
            this.occurrences = occurrences;
            this.status = status;
            this.message = message;
            this.stackTrace = stackTrace;
        }

        @Override
        public String toString() {
            return occurrences + ", " + status + ", " + message + ", " + stackTrace;
        }
    }

输出

3, Fail, Message 1, Stack 1
2, Fail, Message 2, Stack 2
2, Pass, Message 3, Stack 3

答案 2 :(得分:0)

以下是如何实现上述结果的示例:

这使用@Boris Spider的想法,即将messagestacktrace属性的值串联起来以“分组依据”。尽管在这种特定情况下,最好使用groupingBy收集器,而不是使用toMap收集器。

List<CsvEntity> result = new ArrayList<>(source.stream()
        .collect(Collectors.toMap(c -> c.getMESSAGE() + c.getSTACK_TRACE(),
                 v -> new CsvEntity(v.getOCCURRENCES(), v.getSTATUS(), v.getMESSAGE(), v.getSTACK_TRACE()),
                 (left, right) -> {
                     left.setOCCURRENCES(Integer.toString(Integer.parseInt(left.getOCCURRENCES())
                             + Integer.parseInt(right.getOCCURRENCES())));
                     return left;
                 }, LinkedHashMap::new))
        .values());

请注意,此解决方案使用新数据创建新的CsvEntity对象,但是如果您要更改source列表中的对象,则只需将新的CsvEntity(v.getOCCURRENCES(), v.getSTATUS(), v.getMESSAGE(), v.getSTACK_TRACE())更改为{{1} }。

执行此代码后,将产生以下结果:

Function.identity()