romeucr
romeucr

Reputation: 229

Update a List element based on a HashMap value/key

I have the ArrayList:

List<String> wordsList = new ArrayList<>();
// [eu, quero, voltar, para, praia, e, comer, queijo]

And the HashMap:

Map<String, String> wordsMap = new HashMap<>();
//{v.=voltar, c.=comer, q.=queijo., p.=praia}

I am trying to do: If the list element is equal to map value, then replace the list element by the map key. In this example, the result would be:

// [eu, quero, v., para, p., e, c., q.]

Something that I tried was

      for (String word : wordsList) {
         for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (word.equals(value)) {
               newWordsList.add(key);
            } else {
               newWordsList.add(word);
            }
         }
      }
Result: [eu, eu, eu, eu, quero, quero, quero, quero, v., voltar, voltar, voltar, para, para, para, para, praia, praia, praia, p., e, e, e, e, comer, c., comer, comer, queijo, queijo, q., queijo]

Any help?? thanks!

Upvotes: 0

Views: 2668

Answers (4)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79015

You can simply iterate the wordsMap.entrySet(), find the index of the entry#value in wordsList, and update wordsList at the index with the entry#key.

Demo:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = new ArrayList<>(
                List.of("eu", "quero", "voltar", "para", "praia", "e", "comer", "queijo."));
        Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo.", "p.", "praia");

        for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
            int index = wordsList.indexOf(entry.getValue());
            if (index != -1) {
                wordsList.set(index, entry.getKey());
            }
        }

        System.out.println(wordsList);
    }
}

Output:

[eu, quero, v., para, p., e, c., q.]

Note: List#indexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. Therefore the logic in the solution given above checks for -1 and also, only the first occurrence of the matching value will be replaced. If your list has duplicate elements and you want all occurrences of the matching value to be replaced, you need to find all indices of the matching value and replace them as shown below:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = new ArrayList<>(List.of("eu", "quero", "queijo.", "voltar", "queijo.", "para", "praia",
                "e", "queijo.", "comer", "queijo."));
        Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo.", "p.", "praia");
        
        for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
            List<Integer> allIndices = allIndicesOf(wordsList, entry.getValue());
            for (int index : allIndices) {
                wordsList.set(index, entry.getKey());
            }
        }

        System.out.println(wordsList);
    }

    static List<Integer> allIndicesOf(List<String> list, String str) {
        return IntStream.range(0, list.size())
                .boxed()
                .filter(i -> list.get(i).equals(str))
                .collect(Collectors.toList());
    }
}

Output:

[eu, quero, q., v., q., para, p., e, q., c., q.]

Upvotes: 1

Thibaud Ledent
Thibaud Ledent

Reputation: 1872

Given the list and the map:

List<String> wordsList = Arrays.asList("eu", "quero", "voltar", "para", "praia", "e", "comer", "queijo");
Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo", "p.", "praia");

Then the code below returns your results (without any external dependency):

// If the list element is equal to map value, then replace the list element
// by the map key.In this example, the result would be:

wordsMap.values().stream()
    // If the list contains the map value
    .filter(wordsList::contains)
    .forEach(value -> {
        // Find the corresponding map key
        String mapKey = wordsMap.entrySet()
            .stream()
            .filter(entry -> Objects.equals(entry.getValue(), value))
            .map(Map.Entry::getKey) // It could find several keys if you have the same value for different keys
            .findFirst()
            .orElseThrow(); // It should never happen as we are looping in the map values

        // Find the index and update the list with the map key
        int index = wordsList.indexOf(value);
        wordsList.set(index, mapKey);
    });

System.out.println(wordsList);
// [eu, quero, v., para, p., e, c., q.]

Upvotes: 0

magicmn
magicmn

Reputation: 1914

First step for me would be to create a new map that uses the value as key and the key as value. That is much easier than looping through the old map and checking for values.

Map<String, String> invertedWordsMap = wordsMap.entrySet().stream().collect(Collecotrs.toMap(Map.Entry::getValue), Map.Entry::getKey));
//{voltar=v., comer=c., queijo=q.., praia=p.}

And then I just have to check if the key exists in the map

for (int i = 0; i < wordsList.size(); i++) {
    String word = invertedWordsMap.get(wordsList.get(i));
    if (word != null) {
        wordsList.set(i, word);
    }
}

And here is the obligatory fancy stream answer. Just keep in mind that the old list is replaced and not changed if you use the stream solution.

wordsList = wordsList.stream().map(word -> invertedWordsMap.getOrDefault(word, word)).collect(Collectors.toList());

Upvotes: 4

Atom
Atom

Reputation: 375

I'd use a google HashBiMap<String, String> because it can provide an inverse view of the same map, i.e. In a Map<K,V> you can do both get(K) returns V and get(V) returns K

        // Form the words list
        List<String> wordsList = new ArrayList<String>();
        wordsList.add("eu");
        wordsList.add("quero");
        // etc adding all of the terms you mentioned

        // Form the keyset
        HashBiMap<String, String> wordsMap = HashBiMap.create();
        wordsMap.put("v", "voltar");
        wordsMap.put("c", "comer");
        // etc adding all the terms you mentioned

        List<String> wordsListOut = new ArrayList<String>();

        // Iterating through the wordsList
        for (int i = 0; i < wordsList.size(); i++) {

            // Get the current element
            String element = wordsList.get(i);
            // Does it have an inverse pair?
            String result = wordsMap.inverse().get(element);

            // If it has an inverse pair, add the inverse key. Otherwise, add the element raw.
            wordsListOut.add(result == null ? element : result);

        }

        // Outputs: [eu, quero, v, para, p, e, c, q]
        System.out.println(wordsListOut);

The dependency for HashBiMap is Google Guava:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

Upvotes: 0

Related Questions