【问题标题】:How can I solve the following exercise with streams如何使用流解决以下练习
【发布时间】:2021-12-23 00:31:03
【问题描述】:

在下面的练习中,我应该保留所有包含 SmartLamps 的房间。我怎样才能用流解决这个问题?由于每个 SmartLamp 都有属性 Room,我需要流过房间和灯。我试图用 anyMatch 来做,但找不到可行的解决方案。有人可以帮忙吗? (我知道如何在没有流的情况下解决它)

public class SmartHome {

private final List<Room> rooms;
private final List<SmartLamp> lamps;

public void deleteRooms() {
 rooms.stream().anyMatch(lamps.stream().map(SmartLamp::getRoom));
}
}

代码给出错误: “类型不匹配:无法从 Stream 转换为 Predicate

【问题讨论】:

  • Collections like Lists 有一个方法removeIf
  • 另外,Stream.filter 允许您仅将匹配谓词的元素传递给管道中的下一个操作。
  • 您可以使用.stream() 过滤掉坏房间(.filter())。之后,您可以收集房间并将其分配给您的this.rooms

标签: java functional-programming


【解决方案1】:

anyMatch 的使用并没有错,只是用错了地方:

public void deleteRooms() {
    rooms = rooms.stream().filter(r -> lamps.stream().map(SmartLamp::getRoom).anyMatch(r::equals);
}

但以上内容并不理想,因为您必须遍历每个房间的灯列表。预先提取出现在灯列表中的所有房间会有所帮助:

public void deleteRooms() {
    Set<Room> smartRooms = lamps.stream().map(SmartLamp::getRoom).collect(Collectors.toSet());
    rooms = rooms.stream().filter(r -> smartRomms.contains(r)).collect(Collectors.toList());
}

或使用 List.removeIf

public void deleteRooms() {
    Set<Room> smartRooms = lamps.stream().map(SmartLamp::getRoom).collect(Collectors.toSet());
    rooms.removeIf(r -> !smartRomms.contains(r));
}

【讨论】:

  • 这看起来很棒!但是带有过滤器的第二个示例在不应该使用时使用 not 运算符!流过滤器结果包含所有返回 true :)
  • @bgore 感谢您指出这一点。复制粘贴,没注意。
  • 虽然我可以只用流解决这个问题,但我认为这是不可能的,我们也总是需要使用集合..我正确吗?
  • 你的removeIf不等于rooms.retainAll(smartRomms);吗?
【解决方案2】:

我应该保留所有装有 SmartLamp 的房间。

好的,所以你可以这样做......

public class SmartHome {

private final List<Room> rooms;
private final List<SmartLamp> lamps;

void deleteRoomsWithoutSmartLamps() {
  var goodRooms = roomsWithSmartLamps();
  // This line will remove the bad rooms from the list
  rooms = rooms.stream().filter( r -> goodRooms.contains(r)).collect(toList())
}

// This method gives you a list of rooms with smart lamps
public List<Room> roomsWithSmartLamps() {
 var goodRooms = lamps.stream().filter( lamp -> lamp.isSmartLamp() ).map(lamp -> lamp.getRoom()).filter(room != null)collect(toList());
  
  return goodRooms;
}
}

这能解决您的问题吗?在 cmets 中告诉我。

【讨论】:

  • 没有房间没有灯属性...灯有房间属性
  • 添加了一个编辑。看看吧
  • 我是否更正了此方法只会返回相关房间,但是我需要将该方法应用于 List 并使用流进行更改...
  • 查看原帖的下一次编辑
  • 现在解决你的问题了吗?
【解决方案3】:
lamps.stream().map(SmartLamp::getRoom).anyMatch(rooms::contains);

谓词不需要流,您需要创建一个 lambda room -&gt; ...

但是您已经为映射灯制作了一个流,所以我将从该流开始。真的contains 不是很好,但已经足够好了。

Set&lt;Room&gt; 会更好。

【讨论】:

    【解决方案4】:

    你可以试试

    lamps.stream()
             .map(SmartLamp::getRoom)
             .filter(rooms::contains)
             .collect(Collectors.toSet());
    

    【讨论】:

    • 不错!但这之后需要进行额外的操作,因为我需要更改 List 房间。过滤是完美的,但我可以在这个流中以某种方式对房间应用任何操作吗? (我认为不可能)
    • 是的。那么你应该使用 flatmap() 。
    【解决方案5】:

    我相信 anymatch 不是你想要的。任何匹配都是一个流方法,如果流中的任何内容与您想要的匹配,则返回 true 或 false。

    但不管你想要一个谓词

    它的形式

    List<Room> lampRoomList = lamps.stream().map(SmartLamp::getRoom).ToList()
    //predicate is in the filter method
    List<Room> roomsWithLamps = rooms.stream().filter(room.toroom -> lampRoomList.Contains(Room)).toList();
    

    第二行中的房间表示流中的对象。在你的情况下是一个房间。

    第一行是保存所有房间的列表,所以你不需要为每个房间映射。

    您可以在此处阅读有关谓词的更多信息 https://www.geeksforgeeks.org/java-8-predicate-with-examples/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-23
      • 2014-07-01
      • 1970-01-01
      • 2011-01-22
      • 2021-03-10
      • 1970-01-01
      • 1970-01-01
      • 2014-03-14
      相关资源
      最近更新 更多