"Partly" 减少流
"Partly" reducing a Stream
给定以下上下文:
public interface IAdditive<T> {
/** True if still capable to crunch. */
boolean canCrunch();
/** True if capable to crunch with B. */
boolean canCrunch(T other);
/** Returns a new T which is the sum of this and other */
T crunch(T other);
}
class A implements IAdditive<A> {
..
A crunch(A other) {...}
}
class B extends A {
...
B crunch(B other) {...}
}
class C implements IAdditive<C> {
...
C crunch(C other) {...}
}
现在我想“处理”一个实施流
/** Chrunches the streams where possible */
public Stream<A> crunchStream(Stream s) {
return s.map(...);
}
我坚持我相当幼稚的方法:
public Set<A> collect(Stream<A> stream) {
Set<I> res = new HashSet<>();
Set<I> set = stream
.filter(IAdditive::canCrunch)
.collect(Collectors.toSet());
set.forEach(setItem -> set.stream()
.filter(concurrentItem -> concurrentItem.canCrunch(setItem))
.map(setItem::crunch)
.forEach(res::add));
return res;
}
这应该是有缺陷的。我正在展开流,添加强制性复杂性,如果我希望界面以默认方法提供它,我将不得不使用 rawtypes。
我相信我需要一些帮助:-)
根据您的评论,我认为这就是您想要的:
public static interface Additive<T> {
default public Additive<T> crunch(Additive<T> other) { return null; }
}
public static class A implements Additive<A> {};
public static class B implements Additive<B> {};
public static class C implements Additive<C> {};
/**
* Takes a stream of arbitrary Additives and returns a Set containing
* only one crunched Additive for each type
*
* @param stream additives to crunch
* @return crunched set
*/
public Set<Additive<?>> crunch(Stream<Additive<?>> stream) {
return stream
.collect(Collectors.groupingBy(o -> o.getClass()))
.values().stream()
.map(values -> values.stream().reduce(Additive::crunch).get())
.collect(Collectors.toSet());
}
/**
* Takes a stream of arbitrary Additives and returns a Set containing
* only one crunched Additive for each type
*
* @param stream additives to crunch
* @return crunched set
*/
public Collection<Additive<Object>> crunchMap(Stream<Additive<?>> stream) {
return stream
.collect(Collectors.toMap(k -> k.getClass(), v -> (Additive<Object>) v, (a, b) -> a.crunch(b))).values();
}
两种方法都应该产生所需的输出。他们采用包含任意 Additive
的 Stream,将它们按实际类型分组,然后将相同类型的那些压缩成一个对象,最后 return 一个 Set
或 Collection
每种 Additive
.
只包含一个对象
我列出了两种不同的方法。第一种方法首先分组到地图中,然后处理所有相似的类型。这可能是更容易理解的方法。
第二种方法使用映射收集器,将每个附加值映射到它的 class 作为键,并对值执行空操作,然后在键冲突时,将新值与旧值进行处理值并将其放入地图中。它涉及更多,更难阅读,需要更通用的功能才能真正开始工作。
请注意,将 Stream 作为参数传递没有任何好处 - 只需传递集合。事实上,不鼓励传递流,因为您永远无法确定谁已经对流进行了操作,而谁还没有,这会在流已经关闭时导致异常。
请注意,我没有使用您的 canCrunch
方法,而是依赖于每个类型都可以自我压缩并且只能自我压缩这一事实,但不少于此。这比不能压碎的相同类型的对象更容易执行和处理。如果需要,您需要某种形式来区分它们并相应地更改 classificator。
给定以下上下文:
public interface IAdditive<T> {
/** True if still capable to crunch. */
boolean canCrunch();
/** True if capable to crunch with B. */
boolean canCrunch(T other);
/** Returns a new T which is the sum of this and other */
T crunch(T other);
}
class A implements IAdditive<A> {
..
A crunch(A other) {...}
}
class B extends A {
...
B crunch(B other) {...}
}
class C implements IAdditive<C> {
...
C crunch(C other) {...}
}
现在我想“处理”一个实施流
/** Chrunches the streams where possible */
public Stream<A> crunchStream(Stream s) {
return s.map(...);
}
我坚持我相当幼稚的方法:
public Set<A> collect(Stream<A> stream) {
Set<I> res = new HashSet<>();
Set<I> set = stream
.filter(IAdditive::canCrunch)
.collect(Collectors.toSet());
set.forEach(setItem -> set.stream()
.filter(concurrentItem -> concurrentItem.canCrunch(setItem))
.map(setItem::crunch)
.forEach(res::add));
return res;
}
这应该是有缺陷的。我正在展开流,添加强制性复杂性,如果我希望界面以默认方法提供它,我将不得不使用 rawtypes。
我相信我需要一些帮助:-)
根据您的评论,我认为这就是您想要的:
public static interface Additive<T> {
default public Additive<T> crunch(Additive<T> other) { return null; }
}
public static class A implements Additive<A> {};
public static class B implements Additive<B> {};
public static class C implements Additive<C> {};
/**
* Takes a stream of arbitrary Additives and returns a Set containing
* only one crunched Additive for each type
*
* @param stream additives to crunch
* @return crunched set
*/
public Set<Additive<?>> crunch(Stream<Additive<?>> stream) {
return stream
.collect(Collectors.groupingBy(o -> o.getClass()))
.values().stream()
.map(values -> values.stream().reduce(Additive::crunch).get())
.collect(Collectors.toSet());
}
/**
* Takes a stream of arbitrary Additives and returns a Set containing
* only one crunched Additive for each type
*
* @param stream additives to crunch
* @return crunched set
*/
public Collection<Additive<Object>> crunchMap(Stream<Additive<?>> stream) {
return stream
.collect(Collectors.toMap(k -> k.getClass(), v -> (Additive<Object>) v, (a, b) -> a.crunch(b))).values();
}
两种方法都应该产生所需的输出。他们采用包含任意 Additive
的 Stream,将它们按实际类型分组,然后将相同类型的那些压缩成一个对象,最后 return 一个 Set
或 Collection
每种 Additive
.
我列出了两种不同的方法。第一种方法首先分组到地图中,然后处理所有相似的类型。这可能是更容易理解的方法。
第二种方法使用映射收集器,将每个附加值映射到它的 class 作为键,并对值执行空操作,然后在键冲突时,将新值与旧值进行处理值并将其放入地图中。它涉及更多,更难阅读,需要更通用的功能才能真正开始工作。
请注意,将 Stream 作为参数传递没有任何好处 - 只需传递集合。事实上,不鼓励传递流,因为您永远无法确定谁已经对流进行了操作,而谁还没有,这会在流已经关闭时导致异常。
请注意,我没有使用您的 canCrunch
方法,而是依赖于每个类型都可以自我压缩并且只能自我压缩这一事实,但不少于此。这比不能压碎的相同类型的对象更容易执行和处理。如果需要,您需要某种形式来区分它们并相应地更改 classificator。