-2

I am tasked with the following problem: given an array of IngredientPortions (an object i made), if two of the elements in the IngredientPortions are the same Ingredient (Ingredient is another object that is a component of IngredientPortion objects), I am supposed to combine the IngredientPortion elements.

For example, if the IngredientPortion array I am given has two elements, such as an avacodo portion of say 1.5 oz, and another avocado portion of 2.0 oz, I should produce a new IngredientPortion array of 1 element: an avocado of 3.5 oz.

I am not sure how to do this, but I was thinking of using a hashmap of Strings as keys, representing the ingredient name, and values of IngredientPortion objects. If the hashmap already has a key of the given ingredientPortion.getName(), i would put in that specific ingredientPortion for that key, but I'm not sure how to combine the ingredientPortion amounts. Would it automatically combine it or would it store it as two different ingredientPortions under that one key??? Thanks in advance!

etnie1031
  • 81
  • 3
  • 12
  • `map.put(duplicatePortion.getName(), new IngredientPortion(duplicatePortion.getName(), alreadyStoredPortion.quantity + duplicatePortion.quantity)` – JB Nizet Feb 23 '17 at 20:00
  • Possible duplicate of [HashMap with multiple values under the same key](http://stackoverflow.com/questions/4956844/hashmap-with-multiple-values-under-the-same-key) – nhouser9 Feb 23 '17 at 20:00
  • You have not provided your existing code or shown the definition of the map, specifically the type of the entry value. Is it a `Double`, `BigDecimal` or a custom class? – Jim Garrison Feb 23 '17 at 20:18

3 Answers3

1

If your hashmap is storing values, then you can use this to stuff a value in it. This works whether it's the first ingredient (i.e. it's not in the map) or it's the second one (which needs to be added to the value already in the map:

map.put(ingredientKey, map.getOrDefault(ingredientKey, 0.0) + ingredientAmount);
Dave C
  • 1,572
  • 4
  • 23
  • 34
  • Works only for `Map` (or other numeric type). Portion is probably another object with both a quantity and unit of measurement. – Jim Garrison Feb 23 '17 at 20:16
  • @JimGarrison you are right! Luckily I managed to get what I wanted with some other stackoverflow users' help. – etnie1031 Feb 27 '17 at 19:42
0

I am not sure how to do this, but I was thinking of using a hashmap of Strings as keys, representing the ingredient name, and values of IngredientPortion objects.

Sounds good so far.

If the hashmap already has a key of the given ingredientPortion.getName(), i would put in that specific ingredientPortion for that key, but I'm not sure how to combine the ingredientPortion amounts. Would it automatically combine it or would it store it as two different ingredientPortions under that one key???

Obviously, there's no problem when handling an IngredientPortion whose name is not already enrolled as a key in your map. When the key is already enrolled, however, putting a new value into the map with that same key will simply replace the previous value assigned to that key, not somehow combine the values. The documentation for the Map interface should be clear about that.

Indeed, how can you even hope a Map would automatically combine values when how to do so and even whether it's possible to do so depends on the type of the values? It sounds like you might not be certain how to form such a combination. If that's so, then figuring that out must be your first priority. That's, again, a question specific to the type, so we've no way to advise you about the details.

Once you know how to combine these objects in a suitable way, use that. For example, look up each name in the map, and depending on whether it is found, either insert or replace its value.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • thanks so much! I now filled the map, but how would I convert the values of the map back to an array of ingredientPortion objects? I tried using newArray = ingredientMap.values().toArray() but it gives me an error message saying cannot convert from Object[] to IngredientPortion[] – etnie1031 Feb 23 '17 at 20:50
  • @etnie1031, use the version of `Collection.toArray()` that takes a (suitably-typed) array as its argument. For example, `ingredientMap.values().toArray(new IngredientPortion[ingredientMap.size()])`. – John Bollinger Feb 23 '17 at 21:00
0

I implement two solutions for your problem using the Java 8 streams and the groupingBy method. I hope this will help you.

import java.util.*;
import java.util.stream.Collectors;

public class Main {
    public static class Ingredient {
        private final String name;
        private final int quantity;

        public Ingredient(String name, int quantity) {
            Objects.requireNonNull(name);
            this.name = name;
            this.quantity = quantity;
        }

        public String getName() {
            return name;
        }

        public int getQuantity() {
            return quantity;
        }

        @Override
        public String toString() {
            return "Ingredient{" +
                    "name='" + name + '\'' +
                    ", quantity=" + quantity +
                    '}';
        }
    }

    public static void main(String[] args) {
        Ingredient[] ingredients = new Ingredient[]{
            new Ingredient("banana", 1),
            new Ingredient("cherry", 5),
            new Ingredient("banana", 3),
            new Ingredient("floor", 1)
        };

        // First solution: Group all quantities
        Map<String, List<Integer>> collect = Arrays.stream(ingredients)
                .collect(Collectors.groupingBy(Ingredient::getName, 
                        Collectors.mapping(Ingredient::getQuantity, Collectors.toList())
                ));
        System.out.println(collect);

        // Second solution: Sum all quantities
        Map<String, Integer> sum = Arrays.stream(ingredients)
                .collect(
                     Collectors.groupingBy(Ingredient::getName, 
                     Collectors.summingInt(Ingredient::getQuantity)
                ));
        System.out.println(sum);
    }
}
Valentin Michalak
  • 2,089
  • 1
  • 14
  • 27