Skip to main content
added 5 characters in body
Source Link
Bobby
  • 8.2k
  • 2
  • 35
  • 43
if (curr > keys.length - 1) {
    return;
}
 
Also, your formatting seems to be off in a few cases. I'd suggest to always use an automatic formatter in your workflow so that you never need to worry about the formatting of your code ever again.

---

```java

Also, your formatting seems to be off in a few cases. I'd suggest to always use an automatic formatter in your workflow so that you never need to worry about the formatting of your code ever again.


target.put(currKey, 1);
protected Map<String, Integer> values = new HashMap<>();

public int getValue(String... keys) {
    String key = String.join("---/", keys);
    Integer value = values.get(Integer.valueOf(key));
    
    if (value != null) {
        return value.intValue();
    } else {
        return -1; // Or throw exception here.
    }
}
if (curr > keys.length - 1) {
    return;
}
 
Also, your formatting seems to be off in a few cases. I'd suggest to always use an automatic formatter in your workflow so that you never need to worry about the formatting of your code ever again.

---

```java
target.put(currKey, 1);
protected Map<String, Integer> values = new HashMap<>();

public int getValue(String... keys) {
    String key = String.join("---", keys);
    Integer value = values.get(Integer.valueOf(key));
    
    if (value != null) {
        return value.intValue();
    } else {
        return -1; // Or throw exception here.
    }
}
if (curr > keys.length - 1) {
    return;
}

Also, your formatting seems to be off in a few cases. I'd suggest to always use an automatic formatter in your workflow so that you never need to worry about the formatting of your code ever again.


target.put(currKey, 1);
protected Map<String, Integer> values = new HashMap<>();

public int getValue(String... keys) {
    String key = String.join("/", keys);
    Integer value = values.get(Integer.valueOf(key));
    
    if (value != null) {
        return value.intValue();
    } else {
        return -1; // Or throw exception here.
    }
}
added 95 characters in body
Source Link
Bobby
  • 8.2k
  • 2
  • 35
  • 43

More information about your use-case would be helpful, whether this is a solution to a problem or an exercise, for example.


Both implementations lack proper checks, though, but you should get the idea.


Given the use case as example, I'd go with flattening/joining the path into a single string (using "/" as separator) and, when adding a new path, increasing the existing value or setting a new one if it does not exist.

More information about your use-case would be helpful, whether this is a solution to a problem or an exercise, for example.


Both implementations lack proper checks, though, but you should get the idea.

Both implementations lack proper checks, though, but you should get the idea.


Given the use case as example, I'd go with flattening/joining the path into a single string (using "/" as separator) and, when adding a new path, increasing the existing value or setting a new one if it does not exist.

Source Link
Bobby
  • 8.2k
  • 2
  • 35
  • 43

More information about your use-case would be helpful, whether this is a solution to a problem or an exercise, for example.


if(curr > keys.length -1) return;

// ... 

Object currVal = target.get(currKey);

Don't shorten variable names just because you can. It makes the code harder to read and harder to maintain.


if(curr > keys.length -1) return;

Ideally you're always use a "full block if" for statements, as it makes it easier to see the return condition.

if (curr > keys.length - 1) {
    return;
}

Also, your formatting seems to be off in a few cases. I'd suggest to always use an automatic formatter in your workflow so that you never need to worry about the formatting of your code ever again.

---

```java
target.put(currKey, 1);

int and Integer are requiring conversion between each other, that's called "boxing" and might or might not be a problem when doing it implicit.


You ain't got any sort of error handling, if I see this right.


So, let's get to the design. If I understand your example right, what you want to do is to have a list of keys, which represent the path through the tree structure, and the last key keeps a counter how often it was added.

There are several ways to achieve that, and the question is what exactly you're trying to achieve to know which one applies.

For every further implementation, we'll assume the following interface:

public class CounterTreeMap {
    public int getValue(String... keys);
    public void putValue(String... keys);
}

You notice that we've already simplified how to use this class, the rest are implementation details. Additionally, I'll skip tests on the input parameters for brevity.

The cheap one

The cheapest solution is to "fake" depth by hashing the input array and having a single Map. However, this implementation would be able to store a value for the path "A, B" as well as for "A, B, C".

protected Map<Integer, Integer> values = new HashMap<>();

public int getValue(String... keys) {
    int keysHash = Arrays.hashCode(keys);
    // TODO We are missing logic here to handle possible hash collisions.
    Integer value = values.get(Integer.valueOf(keysHash));
    
    if (value != null) {
        return value.intValue();
    } else {
        return -1; // Or throw exception here.
    }
}

The nearly as cheap one

Given the problems from the previous implementation, we can fix at least the possible has collisions by using the full path as key instead.

protected Map<String, Integer> values = new HashMap<>();

public int getValue(String... keys) {
    String key = String.join("---", keys);
    Integer value = values.get(Integer.valueOf(key));
    
    if (value != null) {
        return value.intValue();
    } else {
        return -1; // Or throw exception here.
    }
}

Now that solves the possible hash collisions, but still allows us to store values at each node, basically. That might even be wanted, I don't know, you never specified.

The one with the many maps

As you've done, we can build a hierarchy of Maps, however, I'd base decisions on the type of the encountered leaf.

Recursive implementation:

protected Map<String, Object> tree = new HashMap<>();

public int getValue(String... keys) {
    return getValue(tree, keys, 0);
}

protected int getValue(Map<String, Object> branch, String[] keys, int currentKeyIndex) {
    String key = keys[currentKeyIndex];
    Object value = branch.get(key);
    
    if (value == null) {
        return -1; // Or throw an exception here.
    } else if (value instanceof Integer) {
        return ((Integer)value).intValue();
    } else if (value instanceof Map<?, ?>) {
        return getValue((Map<String, Object)value, keys, currentKeyIndex + 1)
    }
}

Implementation using a loop instead:

protected Map<String, Object> tree = new HashMap<>();

public int getValue(String... keys) {
    Map<String, Object> branch = tree;
    int currentKeyIndex = 0;
    
    while (branch != null) {
        String key = keys[currentKeyIndex];
        Object value = branch.get(key);
        
        if (value == null) {
            return -1; // Or throw an exception here.
        } else if (value instanceof Integer) {
            return ((Integer)value).intValue();
        } else if (value instanceof Map<?, ?>) {
            branch = (Map<String, Object)value;
            currentKeyIndex++;
        }
    }
}

Both implementations lack proper checks, though, but you should get the idea.