Java 按自定义变量和 return 同一对象分组
Java group by custom variable and return same object
我想通过自定义变量 (myHash) 计算列表中重复项的数量
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
这将通过 id 计算重复项,它是散列和 equals 函数中的值。我如何通过自定义变量来计算它?在我的例子中是 byte[] myHash
我的POJO:
public class PersonHash implements Serializable {
private Long id;
private byte[] myHash;
....
}
如果 myHash
不是 equals
和 [= 的标识符和一部分,则不能按 myHash
分组并获取 PersonHash
的实例作为键17=].
如果 myHash
不是 equals
和 hashCode
的一部分,
为 myHash
添加 getter
PersonHash {
getMyHash() {...}
}
并使用
Map<byte[], Long> result = list.stream()
.collect(Collectors.groupingBy(PersonHash::getMyHash, Collectors.counting()));
之后,您可以将 list
与 results
进行匹配,以找到具有给定哈希值的对象。
或使用
Map<byte[], List<PersonHash>> result = list.stream()
.collect(Collectors.groupingBy(PersonHash::getMyHash));
获取具有相同 myHash
值的 PersonHash
的列表。
您必须覆盖对象的 equals
和 hashCode
函数。然后你可以用 Function.identity()
来做到这一点。我已经覆盖了如下这些功能:
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PersonHash personHash = (PersonHash) o;
return hashCompare(personHash) == 0;
}
@Override
public int hashCode() {
return myHash.length;
}
public int hashCompare(PersonHash other) {
int i = this.myHash.length - other.myHash.length;
if (i != 0) {
return i;
}
for (int j = 0; j < this.myHash.length; j++) {
i = this.myHash[j] - other.myHash[j];
if (i != 0) {
return i;
}
}
return 0;
}
现在使用以下代码:
PersonHash personHash1 = new PersonHash();
personHash1.setId(1L);
personHash1.setMyHash(new byte[]{1, 2, 3});
PersonHash personHash1_2 = new PersonHash();
personHash1_2.setId(3L);
personHash1_2.setMyHash(new byte[]{1, 2, 3});
PersonHash personHash2 = new PersonHash();
personHash2.setId(2L);
personHash2.setMyHash(new byte[]{4, 5, 6});
List<PersonHash> list = new LinkedList<>();
list.add(personHash1);
list.add(personHash1_2);
list.add(personHash2);
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.forEach((k, v) -> System.out.println(Arrays.toString(k.getMyHash()) + " " + v));
您将得到以下输出:
[4, 5, 6] 1
[1, 2, 3] 2
PS:请写出更好的hashCode()
函数,我只是想演示一下。
编辑: 正如@WJS 评论的那样,我们可以像这样覆盖 equals
方法,我们不再需要 hashCompare
函数:
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
return Arrays.equals(myHash,((PersonHash) ob).getHash());
}
另一种不更改当前 pojo 的方法(对 equals 和 hashcode 的更改可能会在其他地方导致错误)可能是按 myHash
字段对列表进行排序,然后您可以使用原子引用来构建您的地图
List<PersonHash> list // your list
Comparator<PersonHash> byMyHash = (a,b) -> Arrays.compare(a.getMyHash(),b.getMyHash());
BiPredicate<PersonHash,PersonHash> pred = (a,b) -> Arrays.equals(a.getMyHash(),b.getMyHash());
list.sort(byMyHash);
AtomicReference<PersonHash> ai = new AtomicReference<>(list.get(0));
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(ph -> {
if (pred.test(ph,ai.get())){
return ai.get();
}
else {
ai.set(ph);
return ph;
}
} , Collectors.counting()));
System.out.println(result);
我想通过自定义变量 (myHash) 计算列表中重复项的数量
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
这将通过 id 计算重复项,它是散列和 equals 函数中的值。我如何通过自定义变量来计算它?在我的例子中是 byte[] myHash
我的POJO:
public class PersonHash implements Serializable {
private Long id;
private byte[] myHash;
....
}
如果 myHash
不是 equals
和 [= 的标识符和一部分,则不能按 myHash
分组并获取 PersonHash
的实例作为键17=].
如果 myHash
不是 equals
和 hashCode
的一部分,
为 myHash
PersonHash {
getMyHash() {...}
}
并使用
Map<byte[], Long> result = list.stream()
.collect(Collectors.groupingBy(PersonHash::getMyHash, Collectors.counting()));
之后,您可以将 list
与 results
进行匹配,以找到具有给定哈希值的对象。
或使用
Map<byte[], List<PersonHash>> result = list.stream()
.collect(Collectors.groupingBy(PersonHash::getMyHash));
获取具有相同 myHash
值的 PersonHash
的列表。
您必须覆盖对象的 equals
和 hashCode
函数。然后你可以用 Function.identity()
来做到这一点。我已经覆盖了如下这些功能:
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PersonHash personHash = (PersonHash) o;
return hashCompare(personHash) == 0;
}
@Override
public int hashCode() {
return myHash.length;
}
public int hashCompare(PersonHash other) {
int i = this.myHash.length - other.myHash.length;
if (i != 0) {
return i;
}
for (int j = 0; j < this.myHash.length; j++) {
i = this.myHash[j] - other.myHash[j];
if (i != 0) {
return i;
}
}
return 0;
}
现在使用以下代码:
PersonHash personHash1 = new PersonHash();
personHash1.setId(1L);
personHash1.setMyHash(new byte[]{1, 2, 3});
PersonHash personHash1_2 = new PersonHash();
personHash1_2.setId(3L);
personHash1_2.setMyHash(new byte[]{1, 2, 3});
PersonHash personHash2 = new PersonHash();
personHash2.setId(2L);
personHash2.setMyHash(new byte[]{4, 5, 6});
List<PersonHash> list = new LinkedList<>();
list.add(personHash1);
list.add(personHash1_2);
list.add(personHash2);
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.forEach((k, v) -> System.out.println(Arrays.toString(k.getMyHash()) + " " + v));
您将得到以下输出:
[4, 5, 6] 1
[1, 2, 3] 2
PS:请写出更好的hashCode()
函数,我只是想演示一下。
编辑: 正如@WJS 评论的那样,我们可以像这样覆盖 equals
方法,我们不再需要 hashCompare
函数:
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
return Arrays.equals(myHash,((PersonHash) ob).getHash());
}
另一种不更改当前 pojo 的方法(对 equals 和 hashcode 的更改可能会在其他地方导致错误)可能是按 myHash
字段对列表进行排序,然后您可以使用原子引用来构建您的地图
List<PersonHash> list // your list
Comparator<PersonHash> byMyHash = (a,b) -> Arrays.compare(a.getMyHash(),b.getMyHash());
BiPredicate<PersonHash,PersonHash> pred = (a,b) -> Arrays.equals(a.getMyHash(),b.getMyHash());
list.sort(byMyHash);
AtomicReference<PersonHash> ai = new AtomicReference<>(list.get(0));
Map<PersonHash, Long> result = list.stream()
.collect(Collectors.groupingBy(ph -> {
if (pred.test(ph,ai.get())){
return ai.get();
}
else {
ai.set(ph);
return ph;
}
} , Collectors.counting()));
System.out.println(result);