1

I am trying to implement some functions to a generic array such as setting the count of the item to int count via method setcount( DT item, int count). I've asked this before and a kind Stack Overflow user has been nice enough to explain that using a hashmap would've been better.

class SimpleHistogram<T> implements Histogram<T>, Iterable<T> {

    private final Map<T, Integer> bins = new HashMap<>();

    public SimpleHistogram() {
        this(List.of());
    }

    SimpleHistogram(List<? extends T> items) {
        for (T item : items) {
            Integer count = bins.getOrDefault(item, 0);
            bins.put(item, count + 1);
        }
    }

    @Override
    public void setCount(T item, int count) {
        bins.put(item, count);
    }

    @Override
    public Iterator<T> iterator() {
        return bins.keySet().iterator();
    }

}
    @Override
    public int getTotalCount() {
        return bins.size();
    }

However, there seems to be an error when I tried to run it using my test cases and it seems that the issue stems from the constructor that I'm provided with.

I've tried to debug the issue but the only solution available is to change from

public SimpleHistogram() {
        this(List.of());
    }

to

public SimpleHistogram(Character[] target) {
            this(List.of());
        }

which would be wrong since it should take in any generic array.

Any suggestions on what changes should I make?

Here are the test cases by the way: public class SimpleHistogramTest {

@Test
public void testHistogram() {
    Character[] target = {'a','b','c','a'};
    Histogram<Character> h = new SimpleHistogram<>(target); //here is where the problem arises
    Iterator<Character> iter = h.iterator();
    int elemCount = 0;
    while(iter.hasNext()) {
        iter.next();
        elemCount++;
    }

    assertEquals(3, elemCount);
    assertEquals(2, h.getCount('a'));
    assertEquals(1, h.getCount('b'));
    assertEquals(1, h.getCount('c'));
    assertEquals(4, h.getTotalCount());
Droid
  • 520
  • 1
  • 7
  • 1
    "There seems to be an error ...." - What is the exact error message? In the `testHistrogram()` method you are passing an array of `Character` objects to the constructor, so there must obviously be a constructor that takes an argument of that type. Note that an array is not a `List`, so the constructor that takes a `List extends T>` is not relevant here. – Jesper Oct 27 '22 at 06:46
  • Just add a constructor that takes a T[]: `public SimpleHistogram(T[] items) { this(Arrays.asList(items)); }` – tgdavies Oct 27 '22 at 06:52
  • A `Character[]` is very similar but not (with little effort) assignable to a `List`. A better/more flexible constructor(which also accepts `Character[]`) would be `SimpleHistogram(T... items) {//as before...` the "`...`" is referred to as ["varargs"](https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html) – xerx593 Oct 27 '22 at 06:53
  • `Integer count = bins.getOrDefault(item, 0); bins.put(item, count + 1);` can be rewritten to this 1-liner: `bins.compute(item, (k, v) -> (v == null) ? 1 : v+1);` – xerx593 Oct 27 '22 at 07:14

1 Answers1

2

You should overload your constructor with a new one which is handle the arrays or have to pass the array as list.

  SimpleHistogram(T[] items) {
    this(Arrays.asList(items));
}

or

 @Test
public void testHistogram() {
    Character[] target = {'a','b','c','a'};
    Histogram<Character> h = new SimpleHistogram<>(Arrays.asList(target)); 
    Iterator<Character> iter = h.iterator();
    int elemCount = 0;
    while(iter.hasNext()) {
        iter.next();
        elemCount++;
    }
}

Or you can use the 3 dot syntax for parameters.

SimpleHistogram(T... items) {
    this(Arrays.asList(items));
}

Formatted code for the comment answer:

Its a little missunderstand naming convention. If you want to add items, so incrase the count is: Check if the HashMap has item with key if yes then get its value and incrase with the count, you can do this by sum them and put the key again with the new value

 public void addCount(T item, int count) {
    if (bins.containsKey(item)){
        bins.put(item, bins.get(item)+count);
    }else{
        bins.put(item, count);
    }
}


public void setCount(T item, int count) {
    bins.put(item, count);
}
Chezo
  • 36
  • 3
  • Thank you for your explanation :) I have one question though which is unrelated to this question but it is related to my code, for my setCount(DT item, int count) method, how can I use the hashmap/hashset to return the new count? – Droid Oct 27 '22 at 07:45
  • so like lets say the count of a DT item is 5 but the count in setCount( DT item, count) is 4, how can I make the new count return 9? – Droid Oct 27 '22 at 07:46
  • 1
    Its a little missunderstand naming convention. If you want to add items, so incrase the count is: Check if the HashMap has item with key if yes then get its value and incrase with the count, you can do this by sum them and put the key again with the new value. https://pastebin.com/9X9C5wcD public void addCount(T item, int count) { if (bins.containsKey(item)){ bins.put(item, bins.get(item)+count); }else{ bins.put(item, count); } } public void setCount(T item, int count) { bins.put(item, count); } – Chezo Oct 27 '22 at 08:52
  • bins.get(item) returns the original count of the item in the map right? – Droid Oct 27 '22 at 10:50
  • like in this i mean bins.put(item, bins.get(item)+count); – Droid Oct 27 '22 at 10:54
  • 1
    exactly, thats how the maps works :) - https://www.geeksforgeeks.org/map-interface-java-examples/ – Chezo Oct 27 '22 at 12:49