我有一系列项目:
class Item {
String type;
boolean flag;
int size;
...
}
有几种可能的类型(例如" a"," b"和" c")因此有几种类型标志值的可能组合({ {1}},...)。我需要折叠具有相同值组合的项目,因此我使用此签名的["a" ; false], ["a" ; true"], ["b" ; false]
方法
collapse
我需要的是将输入项目列表分成具有相同Item collapse(Collection<Item> items)
和type
值的组
flag
所以我可以崩溃每个小组
List<Collection<Item>> getGroups(Collection<Item> items) // method I need
所以我可以创建一个Map of Map或制作一些复合键,但它需要一些我想避免的样板代码。将来我可以有更多的分组属性,因此解决方案不应该在这两个属性上进行硬编码,而是可以轻松扩展到新的属性。
如何做得好呢?这个问题有一个众所周知的解决方案吗?
答案 0 :(得分:3)
您可以使用Collectors.groupingBy:
public static void main(String[] args) {
List<Item> list = new ArrayList<>();
list.add(new Item(1, true, 1));
list.add(new Item(1, true, 2));
list.add(new Item(1, false, 3));
list.add(new Item(1, false, 4));
list.add(new Item(2, true, 5));
list.add(new Item(2, false, 6));
Collection<List<Item>> result = list.stream()
.collect(Collectors.groupingBy(x -> Arrays.<Object>asList(x.keyA, x.keyB)))
.values();
for (List<Item> items : result) {
System.out.println(items);
}
}
static class Item {
Integer keyA;
Boolean keyB;
Integer value;
public Item(Integer keyA, Boolean keyB, Integer value) {
this.keyA = keyA;
this.keyB = keyB;
this.value = value;
}
@Override
public String toString() {
return "Item{" +
"keyA=" + keyA +
", keyB=" + keyB +
", value=" + value +
'}';
}
}
答案 1 :(得分:1)
为了知道哪个Item
在逻辑上等于某些其他Item
进行折叠,我会将其责任放在Item
类本身上。您可以覆盖equals
方法,但是如果您要将它们放在Set
某处,这可能会导致不良结果,因此用于检查的单独方法可能是最好的。
另一种选择是获取将用于此检查的那些字段,并将它们转换为Item
的内部类。然后可以仅为内部类重写equals
和hashCode
,并将其实例用作Map
的键。
然而,这些都不会自动包含您稍后添加的任何新字段。因此,维护类的任何人都要确保将需要包含在check(或equals / hashCode)中的任何内容添加到方法中。
我真正想到的唯一方法就是使用反射。如果必须考虑的任何事情只放在内部类中,那就行了。如果必须直接将它保留在Item
类上,那么定义注释(具有运行时保留)可能很有用。执行检查的代码(或者使用等于/ hashCode)可以反映在类上并使用每个带注释的字段。
注释可能如下所示:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CollapseField {
}
然后像这样使用:
class Item {
@CollapseField
String type;
@CollapseField
boolean flag;
int size;
...
}
使用它的代码然后需要检查哪些字段被注释并获取它们的值(这两个操作都使用反射)并检查与其他对象的相等性以确定哪些属于一起。由于这可能会对性能产生相当大的影响,因此使用缓存来处理类似哈希代码的事情将是一个好主意。
最后,我不确定硬编码使用过的值是否值得,除非你要在大量的类中使用它,否则字段的数量可能变得非常大。
最后,Java似乎有些奇怪,但也许使用属性模式而不是字段可能有意义。虽然你会失去一些类型的安全性。史蒂夫·叶格(Steve Yegge)做了一篇很长但很有趣的帖子:http://steve-yegge.blogspot.be/2008/10/universal-design-pattern.html
这几乎是我能想到的最重要的事情。据我所知,没有标准方法。也许有人知道一些方便的图书馆提供解决方案。
编辑:这是一个示例,其中用于键的字段被制作成一个内部类,它实现equals
和hashCode
,因此它可以用作{{1}的键}}:
Map
import java.util.Objects;
public class Item {
int size;
final Key key;
public class Key {
String type;
boolean flag;
public Key(String type, boolean flag) {
this.type = type;
this.flag = flag;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public int hashCode() {
int hash = 5;
hash = 89 * hash + Objects.hashCode(this.type);
hash = 89 * hash + (this.flag ? 1 : 0);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Key other = (Key) obj;
if (!Objects.equals(this.type, other.type)) {
return false;
}
if (this.flag != other.flag) {
return false;
}
return true;
}
}
public Item(String type, boolean flag, int size) {
key = new Key(type, flag);
this.size = size;
}
public String getType() {
return key.type;
}
public void setType(String type) {
this.key.type = type;
}
public boolean isFlag() {
return key.flag;
}
public void setFlag(boolean flag) {
this.key.flag = flag;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Key getKey() {
return key;
}
}
级别的getter和setter将部分字段委托给Item
。请注意,如果您只浏览Key
,则可能不需要Key
中的getter和setter,因为这些字段可以直接访问包含的类。如果您需要添加必须属于密钥的字段,请将其添加到Item
。如果不能用于识别,请将其直接添加到Key
。如果您必须更新它们,任何体面的IDE都可以轻松自动生成Item
和equals
。
请注意,如果您在某个框架中使用该类进行反射或内省,则此解决方案可能会中断。根据接近的方式,hashCode
中的字段最终可能会被视为Key
的属性(由于getter / setter)。像JPA或直接通过反射接近字段的EJB容器可能无法使用它。
答案 2 :(得分:0)
使用复合键放置我当前的方法,但仍在等待新的想法
$('#test').keyboard({ layout: 'qwerty', usePreview: false});
可以轻松添加新字段,但字符串键看起来不太好。