emanic
emanic

Reputation: 151

How to populate LinkedHashMap with elements of integer array and use key as counter

I need to accept an integer (maxInstances) and an integer array as arguments. Then I need to eliminate the elements in the array that appear more than maxInstances and return the result. Note: the result has to remain in the same order as the original array, hence am using LinkedHashMap. I am having some trouble with this as my Java is rusty. Here is the code that I have so far but this seems to produce just one key value pair in the LinkedHashMap. So I am stuck here right now. :( I have not gotten to the part where I make the new array with the eliminated elements, so the return is just a placeholder. All ideas are welcome!

public static int[] answer(int[] data, maxInstances n) {
  if (data.length >= 100) {
   throw new IllegalArgumentException
    ("Too many IDs!");
  } else {
    int[] possibleNumbers = new int[100];
    LinkedHashMap<Integer, Integer> result = new LinkedHashMap<Integer, Integer>();

    for (int i = 0; i < data.length; ++i) {
      possibleNumbers[data[i]] = possibleNumbers[data[i]] + 1;
      result.put(data[i], possibleNumbers[data[i]]);

      // Get a set of the entries
      Set set = result.entrySet();

      // Get an iterator
      Iterator y = set.iterator();

      // Display elements
      while(y.hasNext()) {
         Map.Entry me = (Map.Entry)y.next();
         System.out.print(me.getKey() + ": ");
         System.out.println(me.getValue());
      }
      System.out.println();

    return data;
}

Upvotes: 1

Views: 1215

Answers (3)

fps
fps

Reputation: 34470

Using Java 8 features, you could iterate the array and create a map that stores each element's count. Then, iterate the array again and keep only the elements whose count is less than or equal to the given maxInstances value:

public static int[] answer(int[] data, int maxInstances) {

    Map<Integer, Integer> map = new HashMap<>();

    Arrays.stream(data).forEach(n ->
        map.merge(n, 1, (a, b) -> a + b));

    return Arrays.stream(data)
        .filter(n -> map.get(n) <= maxInstances)
        .toArray();
}

Usage:

int[] result = answer(new int[]{1, 2, 3, 3, 3, 2, 1, 0, 3}, 3);

System.out.println(Arrays.toString(result)); // [1, 2, 2, 1, 0]

Here's a variant that uses jdk's collectors to create the counts map:

public static int[] answer(int[] data, int maxInstances) {

    Map<Integer, Long> map = Arrays.stream(data)
        .boxed()
        .collect(Collectors.groupingBy(
            Function.identity(),
            Collectors.counting()));

    return Arrays.stream(data)
        .filter(n -> map.get(n) <= maxInstances)
        .toArray();
}

Upvotes: 0

marekzbrzozowa
marekzbrzozowa

Reputation: 392

I guess your main problem is not rusty java but rather rusty algorithmic thinking. If I correctly understand your problem you could use any map. Numbers from input table should be used as keys. Values of this map should be used as counters. If key is not found yet new item should be added to map with value 1. If found then value should be incremented. If value is not bigger then maxInstances then you should append input element to list with results

Upvotes: 0

Michael Markidis
Michael Markidis

Reputation: 4191

Here's my take on it. You really don't need a LinkedHashMap if you want to return an array - just use the input array to drive the order.

public static int [] answer (int [] data, final int maxInstances)
{
    if (data.length >= 100)
    {
        throw new IllegalArgumentException("Too many IDs!");
    }
    else
    {
        // build a frequency map
        Map<Integer, Integer> frequencyMap = new HashMap<>();
        for (int e : data)
        {
            Integer val = frequencyMap.get(e);
            if (val == null)
                frequencyMap.put(e, 1);
            else
                frequencyMap.put(e, val + 1);
        }

        // build a list with the values that appear no more than maxInstances
        List<Integer> newData = new ArrayList<>();
        for (int e : data)
        {
            if (frequencyMap.get(e) <= maxInstances)
                newData.add(e);
        }

        // convert the list to an int []
        int [] ret = new int[newData.size()];
        for (int i = 0; i < ret.length; i++)
            ret[i] = newData.get(i);

        return ret;
    }
}

Usage:

public static void main (String [] args)
{
    int [] data = { 1, 2, 1, 5, 2, 3, 1 };
    int [] ret = answer(data, 2);

    // no 1s will be present in the output
    System.out.println(Arrays.toString(ret));
}

Output:

[2, 5, 2, 3]

Upvotes: 2

Related Questions