Java Лямбда для сопоставления списка с картой (x[0] -> приращение от начального значения)

#java

Вопрос:

У меня есть Listlt;Object[]gt; events место, где [0] в каждой строке указан идентификатор, который мне нужен. Также у меня int startSeq есть определенный начальный номер.

Мне нужно получить Maplt;Integer,Integergt; идентификатор события where -gt; startSeq igt; , где i-приращение на 1 от startSeq .

Пример:

 int startSeq = 6; Listlt;Object[]gt; events = dao.getEvents(); // ((Object[])events.get(0))[0] = 200676, ((Object[])events.get(1))[0] = 204561, ... 200676 -gt; 6 204561 -gt; 7 205156 -gt; 8  

Проблема: Если я использую IntStream опцию в качестве основы для своего потока, у меня нет способа отслеживать индекс списка (ключа) в toMap :

 Maplt;Integer,Integergt; map = IntStream.range(startSeq, startSeq  events.size())  .boxed().collect(Collectors.toMap(  x -gt; /* Can't track List, no relation to IntStream*/  Function.identity()))  

Если я использую опцию потока списка в качестве основы, я не смогу отслеживать последовательное увеличение значения toMap :

 Maplt;Integer,Integergt; map = events.stream().collect(Collectors.toMap(  x -gt; (Integer)x[0],   y -gt; /* How to relate i increment from startSeq? */)  

Ответ №1:

Вы можете выполнить итерацию по диапазону (startSeq, startSeq events.size()) и вычесть startSeq из каждого индекса, чтобы сопоставить элементы списка:

 int startSeq = 6; Listlt;Object[]gt; events = List.of(new Object[]{200676,"foo"}, new Object[]{204561,"bar"}, new Object[]{205156,"baz"});  Maplt;Integer,Integergt; map =  IntStream.range(startSeq, startSeq   events.size())  .mapToObj(i -gt; Map.entry((Integer)(events.get(i-startSeq)[0]), i))  .collect(Collectors.toMap(Entry::getKey, Entry::getValue));  System.out.println(map);  

Если вам нужно, сохраняйте порядок вставки:

 .... .collect(Collectors.toMap(Entry::getKey, Entry::getValue,(x, y) -gt; y, LinkedHashMap::new));  

Ответ №2:

Одним из подходов было бы сделать следующее:

 final int startSeq = 6; final Listlt;Object[]gt; events = List.of(new Object[] {1}, new Object[] {2}, new Object[] {3}); Maplt;Integer,Integergt; map = IntStream.range(0, events.size())  .boxed().collect(Collectors.toMap(i -gt; (Integer)events.get(i)[0], i -gt; startSeq   i));  

Пожалуйста, обратите внимание, что это может сработать только в том случае, если startSeq и events может быть сделано final или member изменено.

Ответ №3:

Воспользуйся AtomicInteger :

 AtomicInteger startSeq = new AtomicInteger(6); Maplt;Integer, Integergt; map = events  .stream()  .collect(Collectors.toMap(  x -gt; (Integer)x[0],   x -gt; startSeq.getAndIncrement()  ));  

или int[]

 int[] startSeq = {6}; Maplt;Integer, Integergt; map = events  .stream()  .collect(Collectors.toMap(  x -gt; (Integer)x[0],   x -gt; startSeq[0]    ));  

Комментарии:

1. Могу ли я сделать это без int[] массива, точно так же startSeq ?

2. Не используйте операции с отслеживанием состояния в потоках.

3. @gene.b, нет, как объяснялось ранее startSeq , должно быть фактически окончательным

Ответ №4:

Ты мог бы сделать это вот так. Возможно, вам придется немного изменить способ разыменования объекта события, о котором вы упомянули.

  • потоковая передача индексов для размера массива
  • сопоставьте значение и индекс с массивом
  • затем соберите значения из массива и поместите их на карту.
 int startSeq = 6; Maplt;Integer, Integergt; map = IntStream.range(0, events.size())  .mapToObj(i -gt; new int[] { (int)events.get(i)[0], i   startSeq })  .collect(Collectors.toMap(arr -gt; arr[0],  arr -gt; arr[1]));