2016-02-26 3 views
2

У меня есть HashMap<Integer, Integer>, могут быть повторяющиеся значения для уникальных ключей. Есть ли способ конвертировать HashMap в Set<Integer>, который содержит уникальные целые числа ключей и значений.Объединить ключи и значения HashMap с набором

Это может быть сделано в двух циклах, итерации по клавишам() и .values ​​(). Я хотел бы знать, возможно ли это в потоках java 8.

+1

, пожалуйста, изучите класс «Коллекции». Класс полезности, который содержит все виды методов для преобразования сортировки и многое другое –

+0

@ VikrantKashyap Dude Я знаю, что это разрешимо. Я смотрю, есть ли способ сделать это в потоке java8. – Prozac

+1

«Для уникальных ключей могут быть повторяющиеся значения». это утверждение не имеет смысла. Если что-то уникально, у него нет дубликатов. Ключи уникальны по определению. – Raedwald

ответ

7

Вы можете использовать функцию потока, чтобы объединить оба значения и ключи:

Map<Integer, Integer> map = ... 
Set<Integer> total = Stream.concat(
    map.keySet().stream(), 
    map.values().stream() 
).collect(Collectors.toSet()); 

Это использует изображения карты keySet().stream() и values().stream(), чтобы получить поток обоих, а затем соединяет их с помощью Stream.concat, то в конце концов превращает его в набор. Вызов .toSet() предотвращает дублирование элементов, поскольку набор не может содержать повторяющиеся элементы.

Этот трюк также можно использовать, если ключи являются двойными, а значениями являются float, в этом случае java даст наибольший общий класс разделителей, в этом случае это Number.

+0

Awesome. Это то, что я искал. – Prozac

+2

@ YassinHajaj Я предпочитаю [ответ JB Nizet] (http://stackoverflow.com/a/35646442/464306). Он более чистый, более СУХОЙ, только один раз перебирает карту. – gdejohn

+2

Когда ключи являются двойными, а значения являются поплавками, одинаковые числа считаются не равными из-за различного типа объекта. Я сомневаюсь, что есть вариант использования, где это желательно. – Holger

1

Вы можете просто получить все ключи в виде набора, а затем добавить все значения с addAll

Map<Integer, Integer> map = ... 
Set<Integer> set = new HashSet<>(map.keySet()); 
set.addAll(map.values()); 

Если вы действительно хотите использовать Java 8 потоков вы можете сделать следующее, но я не вижу, как это было бы лучше:

Map<Integer, Integer> map = ... 
Set<Integer> set = new HashSet<>(); 
map.keySet().stream().forEach(n -> set.add(n)); 
map.values().stream().forEach(n -> set.add(n)); 

Или смотреть на все другие решения, но на мой взгляд простой addAll работает лучше всего здесь. Это должен быть самый эффективный и, безусловно, самый читаемый способ сделать это.

+0

ОП спрашивает, возможно ли это сделать с потоками Java8 –

+1

@ScaryWombat, но он также считает, что единственной альтернативой является итерация ключей и значений. Лучше использовать двухстрочное решение с использованием addAll(), IMO. –

1

Вы можете перебирать один раз над набором записей, который даст вам все пары. Если вы делаете это через потоки api или нет, это не имеет значения, потому что сложность этой операции остается неизменной.

public class StreamMapTest { 

    public static void main(String[] args) { 
     Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
     map.put(1, 20); 
     map.put(2, 20); 
     map.put(3, 10); 
     map.put(4, 30); 
     map.put(5, 20); 
     map.put(6, 10); 

     Set<Integer> result = map.entrySet().stream() 
      .flatMap(e -> Stream.of(e.getKey(), e.getValue())) 
      .collect(Collectors.toSet()); 

     System.out.println(result); 
    } 
} 
4

Вызов addAll() дважды просто, как ад и очень удобная для чтения, так что должно быть вашим решением. Но если вы хотите, чтобы ваше любопытство было удовлетворено, вы можете использовать это решение на основе потока (менее читаемое, возможно, менее эффективно):

Map<Integer, Integer> map = ...; 
Set<Integer> result = map.entrySet() 
         .stream() 
         .flatMap(e -> Stream.of(e.getKey(), e.getValue())) 
         .collect(Collectors.toSet()); 
Смежные вопросы