【问题标题】:Java 8 Object stream to map troubleJava 8 对象流映射麻烦
【发布时间】:2017-05-24 08:25:10
【问题描述】:

第一篇关于堆栈溢出的帖子。 在Java中,我正在尝试构建一个映射到每个不同字符串的映射,它出现的次数。以下是我的类在我的列表数据中定义对象的代码;

public class MonitoredData {
public String activityLabel;
public LocalTime startTime, endTime;
public LocalTime Period;
public LocalDate startDate, endDate;
long seconds;
public MonitoredData(LocalDateTime _st, LocalDateTime  _et, String _al){
    startTime=_st.toLocalTime();
    endTime=_et.toLocalTime();
    startDate=_et.toLocalDate();
    endDate=_st.toLocalDate();
    activityLabel=_al;
    Period=LocalTime.from(endTime);
    Period=Period.minusHours(_st.getHour());
    Period=Period.minusMinutes(_st.getMinute());
    Period=Period.minusSeconds(_st.getSecond());
    seconds=Period.getHour()*3600+Period.getMinute()*60+Period.getSecond();
}

从这个列表中,我正在尝试构建一个统计每个字符串出现次数的映射,即activityLabel。 我希望我已经足够清楚了,谢谢。流应映射到 activityLabel 字符串,并简单地计算对象列表中每个不同 activityLabel 字符串的出现次数。

我找到了this,这有点像我想要的,但我仍然无法让它工作,而且它已经困扰我将近一天了。 这是我尝试的第一件事,因为它似乎适用于字符串对象。 Map<String, Long> collect = wordsList.stream().collect(groupingBy(Function.identity(), counting()));

但是,在看到它无法编译之后,我尝试随机调整一些东西,但并没有真正了解发生了什么。 我读了this 整篇文章,我不能说我什么都没学到,但我仍然没有找到答案。

【问题讨论】:

  • 你自己做了什么?您说您已经尝试了一天,但并没有真正显示出太多证据 - 您是否有与您尝试过的内容相关的具体问题,或者您只是要求某人为您编写代码?
  • 你到底尝试了什么?出了什么问题?
  • 我分别使用了时间和日期,以便能够更轻松地编辑周围的日期和时间,我不知道之间的功能,刚刚查了一下。
  • @Diliglont 你不能编辑日期和时间,它们是不可变的。

标签: java list object dictionary java-stream


【解决方案1】:

您所展示的代码上的一些 cmets。

  • 为什么要单独存储时间和日期而不是直接存储 LocalDateTimes?
  • Period=LocalTime.from(endTime); is unnecessary:LocalTime` 是不可变的。
  • 句号是一个字段,应该以小写开头。
  • 您可能想要编写 seconds = ChronoUnit.SECONDS.between(startTime, endTime) 而不是复杂的计算。
  • 您可能应该将您的字段设为private(至少,如果合适,应设为final

所以你的班级可能是这样的:

public class MonitoredData {
  private final String activityLabel;
  private final LocalDateTime start;
  private final LocalDateTime end;
  private final long seconds;

  public MonitoredData(LocalDateTime start, LocalDateTime end, String activityLabel) {
    this.start = start;
    this.end = end;
    this.activityLabel = activityLabel;
    this.seconds = ChronoUnit.SECONDS.between(start.toLocalTime(), end.toLocalTime());
  }

  public String getActivityLabel() {
    return activityLabel;
  }

  //other getters
}

您的计数操作如下所示:

List<MonitoredData> list = ...;
Map<String, Long> activityCount = list.stream()
                            .map(MonitoredData::getActivityLabel)
                            .collect(groupingBy(al -> al, counting()));

(需要静态导入:import static java.util.stream.Collectors.groupingBy;import static java.util.stream.Collectors.counting;)。

【讨论】:

  • 好吧,看起来好多了。在我的原始代码中,期间是开始时间和结束时间之间的差异,我怎样才能以更优雅的方式做到这一点?我会假设 start.minus(end) 不会导致它们之间的差异作为 LocalDateTime 对象。
  • @Diliglont 你可能想看看Durationdocs.oracle.com/javase/8/docs/api/java/time/Duration.html
【解决方案2】:

您可以使用 activityLabel 属性将列表中的元素映射到String,然后使用groupingBy 对相同的字符串进行分组,并使用counting 来获取它们的计数。

LocalDateTime now = LocalDateTime.now();
List<MonitoredData> data = Arrays.asList(new MonitoredData(now, now, "foo"),
        new MonitoredData(now, now, "foo"), new MonitoredData(now, now, "bar"),
        new MonitoredData(now, now, "foo"), new MonitoredData(now, now, "blub"));

Map<String, Long> counts = data.stream()
        .map(md -> md.activityLabel)
        .collect(Collectors.groupingBy(s -> s, Collectors.counting()));

System.out.println(counts);
// {bar=1, foo=3, blub=1}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多