Java 需要使用算法建议从列表中获取对象
我有一个对象列表:Java 需要使用算法建议从列表中获取对象,java,algorithm,Java,Algorithm,我有一个对象列表: class MyObj{ String name; int value; ... } 此列表中的对象可以具有相同的名称,但值不同 List<MyObj> list = new ArrayList<>(); list.add(new MyObj("name1", 31)); list.add(new MyObj("name1", 442)); list.add(new MyObj("name2", 213)); list.add(new MyObj("
class MyObj{
String name;
int value;
...
}
此列表中的对象可以具有相同的名称,但值不同
List<MyObj> list = new ArrayList<>();
list.add(new MyObj("name1", 31));
list.add(new MyObj("name1", 442));
list.add(new MyObj("name2", 213));
list.add(new MyObj("name1", 31));
list.add(new MyObj("name2", 341));
list.add(new MyObj("name3", 131));
List List=new ArrayList();
增加(新MyObj(“名称1”,31));
添加(新MyObj(“名称1”,442));
添加(新MyObj(“名称2”,213));
增加(新MyObj(“名称1”,31));
添加(新MyObj(“名称2”,341));
增加(新MyObj(“名称3”,131));
我的目标是创建另一个列表,其中没有同名的对象。并将所有相同对象的值添加到新对象中
类似这样:newmyobj(“name1”,31+442+31)
我无法想出正确的算法,如何获得所有“重复”对象?如果您将
hashCode
和equals
添加到MyObj
类中,您可以通过以下方式获得不同的列表:
Map<MyObj, MyObj> map = list.stream()
.collect(Collectors.toMap(Function.identity(),
obj -> obj,
(a, b) -> new MyObj(a.name, b.value + a.value)));
map.values()
.forEach(System.out::println);
您可以在一个额外的类中实现第二个列表。 然后,您可以编写一个add函数,如果列表中已经存在同名的对象,则该函数将在列表中进行搜索。 如果是,则将新值添加到当前值,如果不是,则将新项添加到列表中
public class ListHandler {
private List<MyObj> list = new ArrayList<>();
private ListHandler instance = null;
public ListHandler getInstance() {
if (instance == null) {
instance = new ListHandler();
}
return instance;
}
public void addToList(MyObj objectToAdd) {
for (MyObj obj : list) {
if (obj.getName().equals(objectToAdd.getName())) {
obj.addToValue(objectToAdd.getValue());
return;
}
}
list.add(objectToAdd);
}
}
公共类ListHandler{
私有列表=新的ArrayList();
私有ListHandler实例=null;
公共ListHandler getInstance(){
if(实例==null){
实例=新的ListHandler();
}
返回实例;
}
公共无效添加列表(MyObj objectToAdd){
对于(MyObj对象:列表){
if(obj.getName().equals(objectToAdd.getName())){
obj.addToValue(objectToAdd.getValue());
返回;
}
}
list.add(objectToAdd);
}
}
您需要使用类似以下Java代码的内容来迭代列表:
for(MyObj item : list) {
String name = item.getName();
if(haveSeen(name) {
MyObj destinationItem = findDestinationItem(name);
destinationItem.setValue(destinationItem.getValue() + item.getValue());
} else {
addDestinationItem(copy(item));
}
}
return listDestinationItems();
剩下的问题是如何实现haveSeen(字符串名称)
,findDestinationItem(字符串名称)
,addDestinationItem(字符串名称)
和listDestinationItems()
您会发现这些映射非常好地映射到
map.contains()
,map.get()
,map.put()
和map.entrySet()
。OO实现这一点的方法是使用Map
字段,但您也可以将Map
传递给这些方法,例如haveSeen(Map seenItems,String name)
我将使用Map:
map = new HashMap()
for el in list:
if map.get(el.name) == null:
map.put(el.name, el)
else
map.put(el.name, new El(el.name, el.value + map.get(el.name).value))
result = map.values()
此算法的复杂性
O(n*hashCodeOfString())
。基本上就是根据名字把你的MyObj收集到地图中。如果名称相同,则组合值:
Map<String,MyObj> map = list.stream()
.collect(Collectors.toMap((MyObj o) -> o.name, myObj -> myObj, (MyObj o1, MyObj o2) -> new MyObj(o1.name, o1.value + o2.value)));
map.forEach((k,v) -> System.out.println(k + " " + v));
然后从映射中获取值并将其转换为新的MyObj列表
List<MyObj> newList = map.values().stream().collect(Collectors.toList());
newList.forEach(System.out::println);
您可以组合这些步骤,而不在两者之间使用贴图。但是我会让你决定。重写hashCode()
并使用HashSet
合并相同的对象。迭代哈希集
,并将其放入新列表中
class MyObj {
private String name;
private int value;
// other fields
// ....
// getter and setter
@Override
public int hashCode() {
return this.getName().hashCode();
}
@Override
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(!(other instanceof MyObj)) {
return false;
}
if(this == (MyObj) other) {
return true;
}
return this.getName().equals(((MyObj)other).getName());
}
}
这只是一个暗示,不是一个完整的答案。我建议在此基础上找出解决方案。这似乎是streams的任务:
Map<String, MyObj> result = list.stream()
.collect(Collectors.toMap(
MyObj::getName,
Function.identity(),
(a, b) -> new MyObj(a.getName(), a.getValue() + b.getValue())));
您可以按如下方式简化上述收集代码:
Map<String, MyObj> result = list.stream()
.collect(Collectors.toMap(
MyObj::getName,
Function.identity(),
MyObj::merge));
您可以使用Java8(假设在MyObj
中存在gettergetName
):
问题中似乎没有算法尝试。。。当
obj1.name.equals(obj2.name)
时,你试着看了多少?在给你这个任务之前,你的老师有没有把你介绍给Map
班?这有什么帮助?你必须保留列表中项目的顺序吗?@slim我没有老师,为什么我需要地图?我的对象不止两个fields@BigCoach好的,您有一个字符串名称
,您需要知道您以前是否见过它。考虑一下<代码> map <代码>可以帮助你解决这个问题。这并不能增加MyObjA中参数的值,这是一个很好的简单易懂的解决方案。我认为您应该在中添加map
声明。e、 g.Mapmap=newhashmap()代码>
class MyObj {
private String name;
private int value;
// other fields
// ....
// getter and setter
@Override
public int hashCode() {
return this.getName().hashCode();
}
@Override
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(!(other instanceof MyObj)) {
return false;
}
if(this == (MyObj) other) {
return true;
}
return this.getName().equals(((MyObj)other).getName());
}
}
Map<String, MyObj> result = list.stream()
.collect(Collectors.toMap(
MyObj::getName,
Function.identity(),
(a, b) -> new MyObj(a.getName(), a.getValue() + b.getValue())));
public MyObj merge(MyObj another) {
return new MyObj(this.getName(), this.getValue() + another.getValue());
}
Map<String, MyObj> result = list.stream()
.collect(Collectors.toMap(
MyObj::getName,
Function.identity(),
MyObj::merge));
Collection<MyObj> myObjects = results.values();
list.stream()
//map names to sum of values associated with them
.collect(Collectors.groupingBy(MyObj::getName, Collectors.reducing(0, MyObj::getValue, Integer::sum))).entrySet()
//transform map to stream of MyObj
.stream().map(e->new MyObj(e.getKey(), e.getValue()))
//collect into list
.collect(Collectors.toList());