Reputation: 151
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
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
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
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