2017-04-24 45 views
2

得到的對象我有對象的列表:此列表中需要與算法建議可從列表

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) ...

我不能想出正確的算法,如何讓所有的「重複」的對象?

+0

似乎沒有要在這個問題的算法嘗試......多少錢,你嚐嚐看的時候'obj1.name.equals(OBJ 2。名)'? –

+1

在給你這個任務之前,你的老師是否有機會向你介紹'Map'類?這可能有什麼幫助? – slim

+1

您是否必須保留列表中項目的順序? – JeremyP

回答

2

你需要通過你的清單,像這樣的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(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)

0

如果添加hashCodeequalsMyObj類,你可以有這樣的獨特列表:

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] 
+1

這並不會將MyObj中的參數值相加 –

+0

@RobinTopper現在是正確的。 – freedev

1

您可以實現第二在額外的班級列表。 然後,您可以編寫一個添加函數,該函數在列表中搜索同名的對象是否已經存在。 如果是這樣,請將新值添加到當前值,否則將新項添加到列表中。

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

+0

一個很好的簡單易懂的解決方案。我想你應該添加'map'的聲明。例如'Map map = new HashMap <>();' – JeremyP

+0

@JeremyP,謝謝。完成 – vhula

3

收集你MyObj s轉換基於名稱的地圖。如果名字是一樣的組合值:

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

覆寫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()); 
    } 
    } 

這是一個提示,而不是一個完整的答案。我會建議找出基於此的解決方案。

1

這似乎對於流的任務:

Map<String, MyObj> result = list.stream() 
    .collect(Collectors.toMap(
     MyObj::getName, 
     Function.identity(), 
     (a, b) -> new MyObj(a.getName(), a.getValue() + b.getValue()))); 

在這裏,我使用Collectors.toMap實用程序,它通過確定映射的鍵和值收集流的元件,接受合併函數是用於在密鑰相同時合併元素。

如果您MyObj類有這個方法:

public MyObj merge(MyObj another) { 
    return new MyObj(this.getName(), this.getValue() + another.getValue()); 
} 

你可以simpify收集代碼上面如下:

Map<String, MyObj> result = list.stream() 
    .collect(Collectors.toMap(
     MyObj::getName, 
     Function.identity(), 
     MyObj::merge)); 

最後,你已經擁有了MyObj集合中的地圖值:

Collection<MyObj> myObjects = results.values(); 
1

您可以使用Java8(屁股超微電極是一個getter getName存在於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());