How to auto increment the key of a hashmap using collectors and stream in java 8

旧巷老猫 提交于 2019-12-11 06:35:36

问题


I am new to Java 8: Streams and Collectors classes.

I am reading a file whose content need to be saved in a LinkedHashMap<Integer, String> where its <keys> are the line numbers of the files and its <values> are the content at each line, respectably.

Here, I want to use the Stream concept but I am not able to use Collectors.toMap to auto-increment the <keys>, which need to be saved in the LinnkedHashMap object. Instead of that I am getting exceptions.

Following is the code which i am trying:

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

回答1:


you can use IntStream.range:

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

Another option would be using the LineNumberReader API.




回答2:


There are many ways to to this. But here I will explain my way:

1. Set the size of a IntStream object.

First, whenever you have a List<E> of objects (i.e. E could be String, Integers, Objects, etc.) you can convert it into a Map<Integer, E> by using the IntStream class. This class is a sequence of primitive int-valued elements that supports sequential and parallel aggregate operations. This means is like a huge counter. If we already have a counter we need to put some limits and the IntStream.range(int start, int end) method will help us. This method will returns a sequential ordered IntStream from start (inclusive) to end (exclusive) by an incremental step of 1. So if you want to create a IntStream with the size of our List use this:

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

2. Prepare a Stream object based on the IntStream object.

Now, we have a counter of the size of your List<E>, but we need a Map<Integer, E>. Well, now we gonna use the IntStream.boxed(). This method returns a Stream consisting of the elements of this stream, each boxed to an Integer. This is a Stream<Integer>. We are almost done.

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

3. Convert the Stream object to a Map object

Finally, we can create the map, using the Stream.collect() method. This method performs a mutable reduction operation on the elements of this stream. This reduction will be complicated if we didn't have the help of Collectors.toMap() method. This collector can be used to collect Stream elements into a Map instance. To do this, we need to provide two functions: keyMapper and valueMapper. The keyMapper will be used for extracting a Map key from a Stream element, and valueMapper will be used for extracting a <value> associated with a given <key>. For our example, we will use a Map<Integer, Integer>. The keyMapper will the values of the steamBoxed stream we can extract, using i -> i, and the valueMapper should be the values of the numbers list we will get those, using i -> numbers.get(i) like this:

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

4. Combine all the steps

These three parts can be combined together in this simple code:

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>

Also, you will find that some authors prefer to use Function.identity() method as a keyMapper, and numbers::get lambda expression as valueMapper. Why they use those expressions? Just for preference. The Function.identity() method will always return the same instance. So, using Function.identity() instead of i -> i might save some memory. However, i -> i is more readable than Function.identity() but because creates its own instance and have a distinct implementation class consume more memory. The :: lambda expression is just a method reference capture.

But, how can I apply this to my solution?

Well, like this:

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>
Alternative
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>



回答3:


try this code:

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



回答4:


Suppose you have List like below:

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

Now you want Output Like below:

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


来源:https://stackoverflow.com/questions/51047522/how-to-auto-increment-the-key-of-a-hashmap-using-collectors-and-stream-in-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!