0

I have an String Array which would be like:

String [] paramEnv = {"key1=value1","key2=value2","key2=value2"};

Now I need to convert it to HashMap.

I have written two methods for it, I want to know which one is better in terms of efficiency.

Method 1:

String param = "";
String paramName = "";
String paramValue = "";
if ((null != paramEnv) && (paramEnv.length > 0)) {
        for (int i = 0; i < paramEnv.length; i++) {
            param = paramEnv[i];
            int indexOfEqualTo = param.indexOf("=");
            paramName = param.substring(0, indexOfEqualTo);
            paramValue = param.substring(indexOfEqualTo + 1);
            hmKeyValFromParamEnv.put(paramName, paramValue);
        }
    }
    return hmKeyValFromParamEnv;

Method 2:

String param = "";
String paramName = "";
String paramValue = "";
if ((null != paramEnv) && (paramEnv.length > 0)) {
        for (int i = 0; i < paramEnv.length; i++) {
            param = paramEnv[i];
            paramName = (param.split("="))[0];
            paramValue = (param.split("="))[1];
            hmKeyValFromParamEnv.put(paramName, paramValue);
        }
    }
    return hmKeyValFromParamEnv;

Please let me know for any better implementation as well.

4
  • 8
    This question appears to be off-topic because it belongs on code review. Commented Dec 19, 2014 at 9:18
  • 1
    Don't call split() two times, call it one time and store the result. Also, set a limit to your split(). Commented Dec 19, 2014 at 9:19
  • 1
    A for-each with only one split, would be more clear and performant. for(String s : paramEnv) { String[] st = s.split("="); map.put(st[0], st[1]); } Commented Dec 19, 2014 at 9:20
  • Well, since both methods rely on the existence of a = character ... they should both be avoided (or improved). Commented Dec 19, 2014 at 9:24

3 Answers 3

2

If you could use Java 8

public class ArrayToMap {

    public static void main(String[] args) {
        String[] arr = new String[]{"key1=value1","key2=value2"};

    Arrays.stream(arr)
            .map(s -> s.split("="))
            .collect(Collectors.toMap(sa -> sa[0], sb -> sb[1], (v1, v2)->v1));
    }
}
  • make stream from array
  • map each array elementy into two element array (spliting)
  • collect it to map with custom merge function

// edit:

add duplicates elimination. It's just an example. You should make your own strategy to eliminate duplicates (if you need some specific).

// edit 2: after comment by @ZouZou change impl into that use custom merge function

// edit 3: If you couldn't use Java 8 then use guava:

class KeyEntry<K, V> implements Map.Entry<K, V> {
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof KeyEntry)) {
            return false;
        }

        KeyEntry keyEntry = (KeyEntry) o;

        if (!key.equals(keyEntry.key)) {
            return false;
        }

        return true;
    }

    @Override
    public String toString() {
        return "{\"KeyEntry\":{" +
                "\"key\": \"" + key + "\"" +
                ", \"value\": \"" + value + "\"" +
                "}}";
    }

    @Override
    public int hashCode() {
        return key.hashCode();
    }

    KeyEntry(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }

    @Override
    public V setValue(V value) {
        throw new UnsupportedOperationException("NO!");
    }

    private final K key;
    private final V value;


}

beacause common Entry impl use key and value in equals we need custom class.

Then we could create something like:

    Map<String, String> m = new HashMap<>();
    ImmutableSet<Map.Entry<String, String>> uniqueKey = FluentIterable.from(new ArrayList<String>(Arrays.asList(arr)))
            .transform(new Function<String, Map.Entry<String, String>>() {
                @Override
                public Map.Entry<String, String> apply(String s) {
                    String[] splited = s.split("=");
                    return new KeyEntry(splited[0], splited[1]) {
                    };
                }
            }).toSet();

    for (Map.Entry<String, String> s : uniqueKey) {
        m.put(s.getKey(), s.getValue());
        System.out.println(s);
    }
  • transform each element to our KeyEntry
  • make Set
  • rewrite to Map
Sign up to request clarification or add additional context in comments.

6 Comments

This does not work in the OP example because there is a duplicated key in the original array.
Use the overloaded method to provide a merge method if you have two similar keys. Since the values are the same, you can do Arrays.stream(paramEnv).map(s -> s.split("=")).collect(Collectors.toMap(s -> s[0], s -> s[1], (v1, v2) -> v1));
Then you could simply distinct before the split. No need for this map to SimpleEntry. And what if you have String[] arr = new String[]{"key1=value1","key2=value2", "key1=value2"};? distinct() won't work. It's better to use the overloaded toMap, which have been designed for that.
Edited and add thath solution
Edited your post to make it more clear you apply a merge function to the values, not to the keys. (k1, k2) -> k1 was a bit confusing. Hope you don't mind :)
|
0

Both have O(n) complexity. To have significant difference in speed you would need very very big paramEnv array.

As commenters have pointed out you can optimize it slightly by storing both parameters of split in array and then put them into map. It is not really clear if you will get any notable speed increase by doing this (my guess is that you will probably not gain that much speed).

Comments

0

I would go with your first implementation as substring would be much faster and efficient (you just go over characters once until you find equal to symbol ) than split which will be based on pattern matching and as describe here.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.