需要建议使用算法从List中获取对象

时间:2017-04-24 15:03:10

标签: 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("name1", 31));
list.add(new MyObj("name2", 341));
list.add(new MyObj("name3", 131));

我的目标是创建另一个List,没有具有相同名称的对象。并将所有相同对象的值添加到新对象中。

像这样:new MyObj("name1", 31+442+31) ......

我无法提出正确的算法,如何让所有&#34;重复&#34;对象

8 个答案:

答案 0 :(得分:3)

我会使用地图:

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())。它基本上是O(n)

答案 1 :(得分:3)

根据名称将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));

打印

name3 MyObj [name=name3, value=131]
name2 MyObj [name=name2, value=554]
name1 MyObj [name=name1, value=504]

然后从地图中获取值并将其转换为MyObj

的新列表
List<MyObj> newList = map.values().stream().collect(Collectors.toList());

newList.forEach(System.out::println);

打印

MyObj [name=name3, value=131]
MyObj [name=name2, value=554]
MyObj [name=name1, value=504]

您可以组合这些步骤,而不是在两者之间使用地图。但是我会把它留给你。

答案 2 :(得分:2)

您需要使用类似Java-ish伪代码的方式遍历列表:

 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(String name)findDestinationItem(String name)addDestinationItem(String name)listDestinationItems()

您会发现这些地图非常适合Map.contains()Map.get()Map.put()Map.entrySet()。 OO方法是使用Map字段,但您也可以将Map传递给这些方法,例如haveSeen(Map<String,MyObj> seenItems, String name)

答案 3 :(得分:2)

覆盖hashCode()并使用HashSet<MyObj>合并相同的对象。迭代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());
    }
  }

这是一个暗示,而不是一个完整的答案。我建议根据这个找出解决方案。

答案 4 :(得分:1)

您可以在额外的课程中实现第二个列表。 然后你可以编写一个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);
    }
}

答案 5 :(得分:1)

这似乎是溪流的任务:

setDT(data_ARIMA, keep.rownames = TRUE)[]
data_ARIMA$dates_intermediate <- date_decimal(as.numeric(data_ARIMA$rn))
data_ARIMA$dates <- as.Date(date_decimal(as.numeric(data_ARIMA$rn)))
data_ARIMA

这里我使用Collectors.toMap实用程序,它通过确定映射的键和值来收集流的元素,接受用于在键相等时合并元素的合并函数

如果您的Map<String, MyObj> result = list.stream() .collect(Collectors.toMap( MyObj::getName, Function.identity(), (a, b) -> new MyObj(a.getName(), a.getValue() + b.getValue()))); 班级有此方法:

MyObj

您可以按照以下方式简化上面的收集代码:

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)); 集合:

MyObj

答案 6 :(得分:1)

您可以使用Java8(假设getName中存在getter MyObj):

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());

答案 7 :(得分:0)

如果您将hashCodeequals添加到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);

返回:

MyObj [name=name3, value=131]
MyObj [name=name2, value=554]
MyObj [name=name1, value=504]