[JAVA] Stream.distinct mit Feldeigenschaften usw. ausführen

So führen Sie Stream.distinct mit Feldern, Eigenschaften, Berechnungsergebnissen usw. aus

Stream.distinct von Java Stream API kann keinen Lambda-Ausdruck als Argument verwenden.

class Item{
	String name,shop;
	int price;
	Item(String n,int p,String s){ name=n; price=p; shop=s; }
	public String toString(){ return name+", "+price+", "+shop; }
}
Item[] items = {
	new Item("item-1",1000,"shop-A"),
	new Item("item-2",1100,"shop-B"),
	new Item("item-3",1200,"shop-C"),
	new Item("item-4",2000,"shop-A"),
	new Item("item-5",2100,"shop-B"),
	new Item("item-6",2200,"shop-C"),
	new Item("item-7",3000,"shop-A"),
	new Item("item-8",3100,"shop-B"),
	new Item("item-9",3200,"shop-C"),
};

Um ein Produkt pro Shop aus dem obigen Array abzurufen, wäre es wie folgt: wenn different einen Lambda-Ausdruck als Argument verwenden könnte:

Stream.of(items)
	.distinct(item->item.shop)
	...

Aber ich kann es nicht so schreiben, also werde ich stattdessen eine Kombination aus Filter und Set verwenden.

Set<String> unique = new HashSet<>();
Stream.of(items)
	.filter(item->unique.add(item.shop))
	.forEach(System.out::println);
	
> item-1, 1000, shop-A
> item-2, 1100, shop-B
> item-3, 1200, shop-C

Der Grund, warum dies gleichbedeutend ist, ist, dass sich Set.add wie folgt verhält.

Wenn das angegebene Element nicht in der Menge enthalten ist, wird es der Menge hinzugefügt und gibt true zurück. Wenn das angegebene Element bereits in der Menge enthalten ist, gibt es false zurück, ohne die Menge zu ändern.

Mit anderen Worten, es kann als bedingter Ausdruck verwendet werden, der für das erste der doppelten Elemente true zurückgibt.

Parallelstrom

HashSet ist jedoch nicht threadsicher und für parallele Streams gefährlich.

Setze unique = new HashSet <> (); // Nicht threadsicher! Stream.of(items) .parallel () // In mehreren Threads verarbeitet! .filter(item->unique.add(item.shop)) .forEach(System.out::println);

Artikel-7.3000, Shop-A // Duplizieren! item-5,2100,shop-B Artikel-1.1000, Shop-A // Duplizieren! item-6,2200,shop-C

Mit einer Geschwindigkeit von ungefähr 1/100 wurde das obige Ergebnis erhalten. Verwenden Sie stattdessen ConcurrentHashMap, das die Parallelität unterstützt, indem Sie es mit Collections.newSetFromMap in ein Set konvertieren.

Set<String> unique = Collections.newSetFromMap(new ConcurrentHashMap<>());
Stream.of(items)
	.parallel()
	.filter(item->unique.add(item.shop))
	.forEach(System.out::println);

> item-6, 2200, shop-C
> item-5, 2100, shop-B
> item-7, 3000, shop-A

Ok

Recommended Posts

Stream.distinct mit Feldeigenschaften usw. ausführen
API-basierte Steuerung mit cancancan
Wie man mit cli jdk etc. von oracle bekommt