2

I want to convert a list to a map where the key is just a counter and it needs to adhere to the order of the list. I currently have this code:

private static Map<String, String> convertListToMap(final List<String> list) {
    AtomicInteger counter = new AtomicInteger(0);
    Map<String, String> map = list.stream().collect(Collectors.toMap((c) -> {
        Integer integer = counter.incrementAndGet();
        return integer.toString();
    }, (c) -> c));

    return map;
}

I have two questions:

  1. In a simple console app test on my desktop, the counter is preserving the order of the list. Can we be sure the order will always be preserved when executed anywhere else?
  2. Is there a better way to code this?
2
  • Question #1 is essentially asking the same thing as stackoverflow.com/questions/29216588/… Commented Feb 26, 2020 at 22:11
  • I edited the 2nd question to be more generic instead of asking for a solution that is not using AtomicInteger. Sorry for the confusion. Commented Feb 26, 2020 at 22:20

3 Answers 3

5

Try it this way.

static Map<String, String> convert(List<String> list) {
    return IntStream.range(0, list.size()).boxed()
            .collect(Collectors.toMap(n -> String.valueOf(n+1), list::get,
                    (a, b) -> a, LinkedHashMap::new));
}

Notes:

  • The Merge function (a, b) -> a is not really contributing to this.
  • The supplier of LinkedHashMap::new ensures order is retained. Unfortunately, there is not a Collector.toMap that permits a Supplier without the merge function.
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. Is this better than using an AtomicInteger? Or are both approaches equally good and it is just a matter of preference?
AtomicInteger is primarily used for situations when you have threads competing for a unique value between them. Unless you are using threads (and perhaps even then) you should not have to about this. And Atomic* methods do incur some overhead in the way they ensure thread safety.
@Naman Nope. I like it. I've got to remember to use method references when applicable. They just don't always occur to me. Thanks!!
@Naman Actually I had to change things. The OP initialized AtomicInteger to 0 but used incrementAndGet so it became 1. Thus I presumed the first number must be a 1. But I still need 0 in my stream to get the first value of the list. And the rangeClosed method makes the last index too long.
@WJS Makes sense, the index to get and one stored in the Map differs, causing the confusion there.
3

Probably you can use IntStream to map index as key to value, and use LinkedHashMap for preserving order

    IntStream.range(0, list.size())
             .mapToObj(i -> new AbstractMap.SimpleEntry<>(String.valueOf(i+1), list.get(i)))
             .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> 1, LinkedHashMap::new));

2 Comments

return type Map<Integer, String> would be incompatible with the method signature unless String.valueOf is used.
map operation would make it incorrect since you cannot get from the list anymore (the new AbstractMap.SimpleEntry<>(i, 10) part). It might move very close to the another answer I've edited but you don't really need to map to SimpleEntry if in the next step you would collect it toMap.
0

Regarding your first question: As long as your number will not change, your order would be preserved. A better solution would be a LinkedList (https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html) where entries are ordered by the sequence you add them (It may be easier, I do not know your application).

Regarding your second question: The AtomicInteger mainly advances due to better thread safety (Performance Difference of AtomicInteger vs Integer). If you are not performing any concurrent operations there should be no noticable difference. Therefore one could use a normal Integer.

2 Comments

Local variables referenced by a lambda must be effectively final. How would a normal integer work?
All correctly implemented List implementations preserve insertion order, not just LinkedList.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.