2015-06-19 2 views
1

Имея простой класс, такие как:Компактный список на основе значения

public class Label { 
    public String id; 
    public double amount; 
} 

И имея список со следующими значениями (список сортируется в порядке amount по возрастанию):

id  amount 
---------------- 
1742  10 
1742  11 
1647  12 
4217  13 
1647  14 
1742  15 

ли есть простой способ скомбинировать список, так что остается только самая низкая сумма для id. Итак, после уплотнения список должен выглядеть следующим образом:

id  amount 
---------------- 
1742  10 
1647  12 
4217  13 

ответ

0

Вот один из способов сделать это. Метод makeUnique() будет содержать только те метки, которые имеют минимальные суммы.

public class Label { 
    public String id; 
    public double amount; 

    public Label(String id, double amount) { 
     super(); 
     this.id = id; 
     this.amount = amount; 
    } 

    public static Map<String, Label> makeUnique(List<Label> list) { 
     Map<String, Label> map = new HashMap<String, Label>(); 

     for (Label label : list) { 
      if(!map.containsKey(label.id)) map.put(label.id, label); 
     } 
     return map; 
    } 

    public static void main(String[] args) { 
     List<Label> list = new ArrayList<Label>(); 
     list.add(new Label("1742", 10)); 
     list.add(new Label("1742", 11)); 
     list.add(new Label("1647", 12)); 
     list.add(new Label("1647", 14)); 
     Map<String, Label> map = makeUnique(list); 
    } 

} 
+0

В списке вопросов сортировка по сумме. Поэтому нет необходимости в части if (map.containKeys). Просто другая часть в порядке. Поэтому лучше использовать if (! Map.containKeys) –

+0

да. обновленный код для этого. Благодаря @Nuri Tasdemir –

0

Много способов сделать это. Как насчет (полностью тестировался, скорее всего, не компилировать):

public static List<Label> deduped(List<Label> yourSortedList) { 
    List<Label> output = new LinkedList<>(); 
    assert yourSortedList.size() > 0; 
    Label lastVal = yourSortedList.get(0); 
    for (Label l : yourSortedList) { 
     if (!lastVal.id.equals(l.id)) { 
      output.add(lastVal); 
      lastVal = l; 
     } 
    } 
    output.add(lastVal); 
    return output; 
} 

Я был бы очень удивлен, если бы не было, по крайней мере одна ошибка в приведенном выше, но, надеюсь, вы получите общее представление.

1

Если я правильно понял, вы хотите удалить двойники из списка объектов Label. Есть несколько простых способов, таких как создание пользовательского компаратор для списка:

Docs: https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html Stack Overflow сообщение: Collections sort(List<T>,Comparator<? super T>) method example

Другой способ заключается в использовании карты, поскольку, насколько я могу сказать вам использовать два значения, поэтому использование подобной TreeMap с пользовательским компаратором^также может быть решением. В противном случае вы можете разработать свой собственный алгоритм сортировки, который также сравнивает объекты друг с другом при сортировке и пропускает двойники на основе вашего критерия. Например, сортировка Buble может быть изменена, чтобы сделать это, а также большинство методов сортировки.

0

Почти все правильно, но когда дело доходит до простого способа

просто использовать java.util.Set

и Переопределение equals() и hashCode() методы класса Label.

Помимо этого Есть так много способов.

Один из способов сделать это

List<Label> originalList = new ArrayList<Label>(); 
      // above conatins your original List 

      List<Label> result = new ArrayList<Label>(); 
      Set<String> label = new HashSet<String>(); 

      for(Label item : originalList) { 
       if(label.add(item.getId()) { 
        result.add(item); 
       } 
      } 

вам нужно иметь метод добытчик getId() в классе

0

Поскольку список уже отсортирован по сумме, вам просто нужно включить объект Ярлык в списке в первый раз. Вы можете создать новый список с точными элементами, если вы используете словарь для хранения id s из уже введенных элементов. Как это:

public static List<Label> compact(List<Label> l) 
    { 
     Set<String> ids = new HashSet<>(); 
     List<Label> toret = new ArrayList<>(); 

     for(Label label: l) { 
      if (!ids.contains(label.id)) { 
       ids.add(label.id); 
       toret.add(label); 
      } 
     } 

     return toret; 
    } 

Antoher возможность, так как мы используем списки, будет делать уплотнению «на месте», то есть, используя один и тот же список.Учтите, что эта возможность использует меньше памяти, но медленнее (поскольку она должна искать элемент «i» для каждого цикла времени, что может быть дорогостоящим в LinkedList).

public static void compactInPlace(List<Label> l) 
{ 
    Set<String> ids = new HashSet<>(); 

    for(int i = 0; i < l.size(); ++i) { 
     if (!ids.contains(l.get(i).id)) { 
      ids.add(l.get(i).id); 
     } else { 
      l.remove(i); 
      --i; 
     } 
    } 

    return; 
} 

Найти код здесь: http://ideone.com/B4Gggt

Надеется, что это помогает.

0

Использование Java 8 потоков вы можете сделать:

import java.util.Optional; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.stream.Collectors; 

public static List<Label> getDistinctMinLabels(List<Label> labels) { 
    return labels 
     .stream() 
     .collect(
      // group by label id 
      // and of each group get the label with the minimum amount 
      Collectors.groupingBy(
       label -> label.id, 
       Collectors.minBy((l1, l2) -> Double.compare(l1.amount, l2.amount)) 
      ) 
     ) 
     .entrySet() 
     .stream() 
     .map(Entry::getValue) 
     .map(optional -> optional.get()) // Collectors.minBy returns an Optional<Label> 
     .collect(Collectors.toList()); 
} 

Эта функция не будет наиболее эффективным, но также работает, когда метки не сортируются.

Смежные вопросы