Как автоматически увеличить ключ hashmap, используя коллекторы и поток в Java 8

Я новичок в Java 8 потоков и коллекционеров.

Я читаю файл, содержимое которого нужно сохранить в connectedHashMap, где ключ - это номер строки файлов, а значения - его содержимое в этой строке.

Здесь я хочу использовать концепцию потока, но я не могу использовать Collectors.toMap для автоинкрементации ключей, которые необходимо сохранить в LinnkedHashMap, но я получаю исключения.

Ниже приведен код, который я пытаюсь

#
        List<String> list = new ArrayList<>();
        Integer count=0;

        try (BufferedReader br = Files.newBufferedReader( Paths.get( fileName ) )) {

            // br returns as stream and convert it into a List
            list = br.lines().collect( Collectors.toList() );


        }
        catch ( IOException e ) {
            e.printStackTrace();
        }

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

        Map<Integer, String> fileNumWithContentMapper = list.stream()
                                               .collect( Collectors.toMap( n->n+1,s1->s1) );
#

2 ответа

Есть много способов это сделать. Но здесь я объясню свой путь:

1. Установите размер IntStream объект.

Во-первых, всякий раз, когда у вас есть List<E> объектов (т.е. E может быть String, Integers, Objectsи т. д.) вы можете преобразовать его в Map<Integer, E> используя IntStream учебный класс. Этот класс представляет собой последовательность примитивных int-значимых элементов, которые поддерживают последовательные и параллельные агрегатные операции. Это значит как огромный счетчик. Если у нас уже есть счетчик, нам нужно установить некоторые ограничения и IntStream.range(int start, int end) метод поможет нам. Этот метод возвращает последовательный порядок IntStream от start (включительно) до end (эксклюзивно) с шагом 1. Таким образом, если вы хотите создать IntStream с размером нашего List использовать этот:

List<Integer> numbers = Arrays.asList(4, 5, 4, 3);
IntStream stream = IntStream.range(0, numbers.size); 

2. Подготовить Stream объект на основе IntStream объект.

Теперь у нас есть счетчик размера вашего List<E>, но нам нужен Map<Integer, E>, Ну, теперь мы будем использовать IntStream.boxed(), Этот метод возвращает Stream состоящий из элементов этого потока, каждый в Integer, Это Stream<Integer>, Мы почти закончили.

Stream<Integer> streamBoxed = stream.boxed();

3. Конвертировать Stream возражать против Map объект

Наконец, мы можем создать карту, используя Stream.collect() метод. Этот метод выполняет изменяемую операцию сокращения над элементами этого потока. Это сокращение будет сложным, если у нас не было помощи Collectors.toMap() метод. Этот сборщик можно использовать для сбора элементов Stream в экземпляр Map. Для этого нам нужно предоставить две функции: keyMapper а также valueMapper, keyMapper будет использоваться для извлечения Map ключ от Stream элемент и valueMapper будет использоваться для извлечения <value> связано с данным <key>, Для нашего примера мы будем использовать Map<Integer, Integer>, keyMapper будут значения steamBoxed поток мы можем извлечь, используя i -> iи valueMapper должны быть значения numbers список получим, используя i -> numbers.get(i) как это:

Map<Integer, Integer> result = streamBoxed.collect(Collectors.toMap(i -> i, i -> numbers.get(i)))

4. Объедините все шаги

Эти три части могут быть объединены в этот простой код:

List<Integer> numbers = Arrays.asList(4, 5, 4, 3);

Map<Integer, Integer> result = IntStream
        .range(0, numbers.size); // IntStream 
        .boxed(); // Stream<Integer>
        .collect(Collectors.toMap(i -> i, i -> numbers.get(i))) // Map<Integer, Integer>

Также вы обнаружите, что некоторые авторы предпочитают использовать Function.identity() метод как keyMapper, а также numbers::get лямбда-выражение как valueMapper, Почему они используют эти выражения? Просто для предпочтения. Function.identity() Метод всегда будет возвращать один и тот же экземпляр. Итак, используя Function.identity() вместо i -> i может сэкономить память Тем не мение, i -> i более читабельно, чем Function.identity() но поскольку создает свой собственный экземпляр и имеет отдельный класс реализации, потребляет больше памяти. :: Лямбда-выражение - это просто захват ссылки на метод.

Но как я могу применить это к моему решению?

Ну вот так:

final List<String> list;

...
// list initialization;
list = br.lines().collect(Collectors.toList());
...

Map<Integer, String> fileNumWithContentMapper = IntStream
        .range(0, list.size()) // IntStream 
        .boxed() // Stream<Integer>
        .collect(Collectors.toMap(i -> i, i -> list.get(i))); // Map<Integer, String>
альтернатива
final List<String> list;

...
// list initialization;
list = br.lines().collect(Collectors.toList());
...

Map<Integer, String> fileNumWithContentMapper = IntStream
        .range(0, list.size()) // IntStream 
        .boxed() // Stream<Integer>
        .collect(Collectors.toMap(Function.identity(), list::get)) // Map<Integer, String>

Ты можешь использовать IntStream.range:

IntStream.range(0, list.size())
         .boxed()
         .collect(Collectors.toMap(Function.identity(), i -> list.get(i)));

Другой вариант будет использовать LineNumberReader API.

Попробуйте этот код:

public static void main(String[] args)  {
    List<String> list = Arrays.asList("A", "B", "C");
    list.forEach( System.out::println );

    AtomicInteger i = new AtomicInteger(0);
    Map<Integer, String> fileNumWithContentMapper = list.stream()
                .collect( Collectors.toMap( n->i.incrementAndGet(),s1->s1));

    System.out.println(fileNumWithContentMapper);
}

Предположим, у вас есть List как ниже:

List<String> list =  Arrays.asList("Vishwa","Ram","Mohan","Sohan");

Теперь вы хотите вывод, как показано ниже:

0  Vishwa
1  Ram
2  Mohan
3  Sohan

public class Someclass{
static int j=0;
static int count(int de){
    return de++;
}
    public static void main(String[] args) {
     List<String> list =  Arrays.asList("Vishwa","Ram","Mohan","Sohan");
        Map<Integer,String> map;
        map = list.stream().collect(Collectors.toMap(s->{count(j);return j++;}, Function.identity()));
        map.forEach((k,v)-> {
                         System.out.print(k+"  ");
                         System.out.println(v);
    });
    }
}
Stream.of("A", "B", "C").collect(TreeMap<Integer, String>::new
    ,(map, element) -> map.put(Optional.ofNullable(map.lastEntry()).map(e -> e.getKey() + 1).orElse(1), element)
    ,(m1, m2) -> {})
    .forEach((i, e) -> System.out.println(i + " " + e));

Печать:

1 A 
2 B
3 C
Другие вопросы по тегам