Damo
Damo

Reputation: 3

How would you update the values in a hashmap based on prior conditions?

Something fundamental about hashmaps and for loops is hard for me to grasp here. What I'm trying to do is add +1 to the value associated with the key based on the Keys method every time the value within the array list is associated with the key string.

So if there are 3 values in the array list that are positive then the hashmap should have the value with the key "positive" updated to 3.

Any help/advice would be appreciated - thank you.

public String Keys(double input){

    if (input > 0){
        System.out.println("positive");
    }
    else if (input < 0) {
        System.out.println("negative");
    }
    else if (input == 0) {
        System.out.println("zero");
    }
    return "";
}

public HashMap<String, Integer> increaseValues(ArrayList<Double> inputs){
    HashMap<String, Integer> hashMap = new HashMap<>();
    hashMap.put("positive", 0);
    hashMap.put("negative", 0);
    hashMap.put("zero", 0);

//What I tried before adding the Keys method.
//This updates the value but the loop won't continue if another input in the 
//arraylist is true.

for (int i = 0; i < inputs.size(); i++){
        double input = inputs.get(i);

        if (input > 0){
           hashMap.put("positive", 1);
        } else if (input < 0){
          hashMap.put("negative", 1);
        } else if (input == 0){
          hashMap.put("zero", 1); }
    return hashMap;
}

public void main(String[] args){
    ArrayList<Double> inputs = new ArrayList<>();
    inputs.add(-4.56);
    inputs.add(-4.66);
    inputs.add(0.0);
    inputs.add(6.0);
    inputs.add(-6.99);
    inputs.add(6.97);   
}

Upvotes: 0

Views: 2493

Answers (4)

nits.kk
nits.kk

Reputation: 5336

The method put of HashMap maps unique keys with values. It replaces the existing value with the new value in case the provided key is already present in the map.

You need to define a method similar to below.

public void addValueToList(Double d, List<Double> inputs , Map<String,Integer> map){
    if( d == null ) return;
    if ( isZero(d) ){
        Integer count =  map.get("zero");
        if(count == null){
            count = 1;
        }else {
             count ++;
        }
        map.put("zero",count);

    }else if( isNegative(d) ) {
        Integer count =  map.get("negative");
        if(count == null){
            count = 1;
        }else {
             count ++;
        }
        map.put("negative",count);
    }else {
        Integer count =  map.get("positive");
        if(count == null){
            count = 1;
        }else {
             count ++;
        }
        map.put("positive",count);
   }
   inputs.add(d);
}

For writing method for comparing the value you can refer https://stackoverflow.com/a/10400718/504133

Upvotes: 0

Boris the Spider
Boris the Spider

Reputation: 61178

Lets start with a quick tidy, lets create an enum and remove those nasty String constants that you don't have defined anywhere:

public enum Sign {
    POSITIVE,
    ZERO,
    NEGATIVE;

    public static Sign of(double d) {
        if (d > 0) {
            return POSITIVE;
        }
        if (d < 0) {
            return NEGATIVE;
        }
        return ZERO;
    }
}

Now we can trivially write a method to increment the appropriate value:

public void increment(final double d, final Map<Sign, Integer> count) {
    count.merge(Sign.of(d), 1, Integer::sum);
}

For a quick test:

final Map<Sign, Integer> count = new EnumMap<>(Sign.class);

increment(0, count);
System.out.println(count);
increment(-1, count);
System.out.println(count);
increment(1, count);
System.out.println(count);
increment(-2, count);
System.out.println(count);
increment(2, count);
System.out.println(count);

Output:

{ZERO=1}
{NEGATIVE=1, ZERO=1}
{POSITIVE=1, NEGATIVE=1, ZERO=1}
{POSITIVE=1, NEGATIVE=2, ZERO=1}
{POSITIVE=2, NEGATIVE=2, ZERO=1}

So how does this magic work? From the documentation for Map.merge

If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null. This method may be of use when combining multiple mapped values for a key.

So it takes the key as the first argument to merge - in the case Sign.of(d); this selects the correct bucket. If the value mapped to that key is null then it simply puts a mapping for the key to the value passed as the second argument - in this case 1. Otherwise it gets a litte more complicated; it takes the value currently mapped to that key and uses the remappingFunction passed as the third argument. This is a BiFunction<V,V,V>, so it takes two arguments of type V, the value type and returns a single one - it merges the two together. Here we use Integer::sum to take the existing value, the new value and return their sum.


But we can go one step further, we can use a Stream to carry this out on an arbitrary double[]:

public Map<Sign, Long> count(final double[] d) {
    return Arrays.stream(d)
            .mapToObj(Sign::of)
            .collect(groupingBy(identity(), () -> new EnumMap<>(Sign.class), counting()));
}

Note: I've used an EnumMap here, which is Map optimised for using an enum as the key.

Upvotes: 2

Malte Hartwig
Malte Hartwig

Reputation: 4555

Map.put(k, v) always overrides your previous value. You can use the "traditional approach":

if (!map.containsKey("positive"))
    map.put("positive", 0);
map.put("positive", map.get("positive") + 1);

or better use the new merge funtction that is added for exactly such cases:

map.merge("positive", 1, (prev, one) -> prev + one);

But this whole logic can be greatly shortened by using Math.signum() and stream collectors:

Map<Double, Long> collect = inputs.stream()
                                  .collect(Collectors.groupingBy(Math::signum,
                                                                 Collectors.counting()));
System.out.println("positive: " + collect.get(1.0));
System.out.println("negative: " + collect.get(-1.0));
System.out.println("zero: " + collect.get(0.0));

Upvotes: 2

lexicore
lexicore

Reputation: 43699

You can solve it pretty concisely with streams. You need a function which turns value into the negative/zero/positive key. Then just group by this key with a counting collector. It's basically a two-liner:

    List<Double> values = Arrays.asList(-4.56,-4.66,0.0, 6.0, -6.99, 6.97);

    Function<Double, String> toKey = v -> v < 0 ? "negative" : (v == 0 ? "zero" : "positive");

    Map<String, Long> result = values
        .stream()
        .collect(Collectors
            .groupingBy(
                 toKey,
                 Collectors.counting()));

Upvotes: 1

Related Questions