Get a least occurred value in a Map - java

i have no idea how to get the value in a map that occurred the least.
problem :
Write a method rarest that accepts a map whose keys are strings and whose values are integers as a parameter and returns the integer value that occurs the fewest times in the map. If there is a tie, return the smaller integer value. If the map is empty, throw an exception.
For example, suppose the map contains mappings from students' names
(strings) to their ages (integers). Your method would return the least
frequently occurring age. Consider a map variable m containing the
following key/value pairs:
{Alyssa=22, Char=25, Dan=25, Jeff=20, Kasey=20, Kim=20, Mogran=25,
Ryan=25, Stef=22} Three people are age 20 (Jeff, Kasey, and Kim), two
people are age 22 (Alyssa and Stef), and four people are age 25 (Char,
Dan, Mogran, and Ryan). So a call of rarest(m) returns 22 because only
two people are that age.
If there is a tie (two or more rarest ages
that occur the same number of times), return the youngest age among
them. For example, if we added another pair of Kelly=22 to the map
above, there would now be a tie of three people of age 20 (Jeff,
Kasey, Kim) and three people of age 22 (Alyssa, Kelly, Stef). So a
call of rarest(m) would now return 20 because 20 is the smaller of the
rarest values.
now i believe that this code give me the smallest int count but how do i get that value?
public static int rarest (Map<String, Integer> map) {
    List<Integer> list = new ArrayList<Integer>();
    for(Integer i: map.values()) {
        list.add(i);
    }
    int min = 0, count = 0;
    for(Integer i: list) {
        count = Collections.frequency(list, i);
if(count < min) {
min = count;
}
    }
    return min;  
}

Keep track of the value of i which corresponds to the lowest count min. This should look familiar:
public static int rarest (Map<String, Integer> map) {
List<Integer> list = new ArrayList<Integer>();
for(Integer i: map.values()) {
list.add(i);
}
int min = Integer.MAX_VALUE, rarestValue = 0;
for(Integer i: list) {
int count = Collections.frequency(list, i);
if(count < min || (count == min && i < rarestValue)) {
min = count;
rarestValue = i;
}
}
return rarestValue;
}

do it like this,
public static int rarest (Map<String, Integer> map) {
List<Integer> list = new ArrayList<>(map.values());
Collections.sort(list); // you need to sort the list first
int min = list.get(0); // this is your bug, min shouldn't start at 0
int count = 0, rarest = 0;
for(Integer i: list) {
count = Collections.frequency(list, i);
if(count < min) {
min = count;
rarest = i;
}
}
return rarest;
}
Your bug is that min shouldn't be initialized at 0 but at the first value of the list
If you don't sort the list first, in case of a tie, you won't necessarily get the youngest

Related

How to find ALL maximum values in a List in Java?

I have a List that stores different numbers, the maximum of them are elements under indices: 2; 4.
I want to print these 2 elements to the console - as the maximum numbers in the array, but the Collections.max () method returns only the first maximum value it finds, that is, only the element at index 2:
List<Integer> numbers = new ArrayList<Integer>();
numbers.add(5);
numbers.add(9);
numbers.add(50);
numbers.add(12);
numbers.add(50);
System.out.println(Collections.max(numbers));
|Output|
50
What should I use instead of method Collections.max() to find ALL maximum values?
this uses one iteration to find them
List<Integer> numbers = new ArrayList<Integer>();
numbers.add(5);
numbers.add(9);
numbers.add(50);
numbers.add(12);
numbers.add(50);
int max = Integer.MIN_VALUE;
int count = 1;
for(int number : numbers){
if(number > max){
max = number;
count = 1;
} else if(number == max){
count++;
}
}
for(int i=0; i<count; i++){
System.out.println(max);
}
There is no given function doing that by default. So what you can do is filtering this list for the given value. This will cause 2 iterations but be simple in code. If you do it in your own loop if it more code but more efficient.
Depending on the amopunt of data you should choose efficient way or readable way.
// 2 iterations - 1st for finding max , 2nd for filter
int maxValue = Collections.max(numbers);
List<Integer> maxValues = numbers.stream().filter(number -> number == max).collect(Collectors.toList()); // only need size? Add .size() at the end
// efficient - just 1 iteration, but not pretty to read.
int currentMax = numbers[0];
int counter = 0;
for(Integer number in numbers) {
if(currentMax == number) {
counter++;
} else if(currentMax < number) {
counter = 1;
currentMax = number;
}
}
max will always find the maximum value and not the occurences. What you want will always have to be done in 2 steps.
// If you start from a List
List<Integer> numbers = Arrays.asList(5, 9, 50, 12, 50);
IntSummaryStatistics numberStats = numbers.stream().collect(Collectors.summarizingInt(Integer::intValue));
numbers.stream().filter(number -> number == numberStats.getMax()).forEach(System.out::println);
// But you can also start from the stream itself
IntSummaryStatistics numberStats = IntStream.of(5, 9, 50, 12, 50).summaryStatistics();
numbers.stream().filter(number -> number == numberStats.getMax()).forEach(System.out::println);
/*
* You can also use the plain max number instead of the summaryStatistics, which is
* more performant but the stream cannot be reuse for e.g. min or average.
* Note here we use equals because we don't use primitive int but Object Integer as it's not an IntSteam
*/
Integer maxInt = numbers.stream().max(Comparator.naturalOrder()).orElseThrow();
numbers.stream().filter(number -> number.equals(maxInt)).forEach(System.out::println);
Comparator.naturalOrder() means that you do not provide a comparator but let Java use it's default comparator which it has for all primitives, boxed primitives and Strings. Sorting words and numbers is a natural thing that is well known and does not require any implementation.
You can first loop through the list to find the max value, and then loop the list again to put max valus and their index to a map.
Map map = new HashMap();
int curMax = 0;
for (int i = 0; i < numbers.size(); i++) {
if (numbers.get(i)>=curMax){
curMax = numbers.get(i);
}
}
for (int i = 0; i < numbers.size(); i++) {
if (numbers.get(i) == curMax){
map.put(i, numbers.get(i));
}
}
System.out.println(map.toString());
Output:
{2=50, 4=50}
You can find the maximal elements by lifting the integer values into a list first and reducing that list:
List<Integer> max = numbers.stream()
.collect(Collectors.reducing(
Collections.singletonList(Integer.MIN_VALUE),
Collections::singletonList,
(l1, l2) -> {
if (l1.get(0) > l2.get(0)) {
return l1;
} else if (l2.get(0) > l1.get(0)) {
return l2;
} else {
List<Integer> l = new ArrayList<>(l1);
l.addAll(l2);
return l;
}
}));

HashMap/ArrayList averaging program

A bit of a beginner with programming so do bear with me.
I've created an ArrayList inside a HashMap so that all my values can be added up to become a sum so that I can then divide the sum, by the number of entries to the ArrayList, which would give me my average... which is all working fine EXCEPT:
My first entry into my ArrayList is always coming back as 0.0 even when in the GUI I'm entering like 45 or whatever. How can I change it so that my ArrayList stops putting 0 on my first entry? As I've created an averaging program that would work if my first ArrayList entry was retrieving the correct entry, as oppose to the 0 it is bringing back everytime.
Here is my code:
public void addModRes( String mod, Integer res ) {
ArrayList<Integer> nums = myMap.get(mod);
if (nums == null) {
nums = new ArrayList<Integer>();
}
double sum = 0;
double test =0;
double avg =0;
for (Integer number : nums) {
sum += number;
}
//except sum is missing out the first entry in the ArrayList
System.out.println("The Sum of all the numbers in the array is " + sum);
nums.add(res);
myMap.put(mod, nums);
test = nums.size();
//System.out.println("This is the size of the array list "+
numbers.size());
avg = sum/test;
System.out.println("this is the average: "+ average);
}
I tried to understand your code and my guess is that you want something like this:
You want a HashMap<String, ArrayList<Interger>> that stores lists of numbers (the ArrayList<Integer> from the HashMap) that can be identified with their id (the String in the HashMap).
Add a new list to the HashMap
Let's assume that we have an instance variable listMap in our class.
public int createList(String listId) {
this.listMap.put(listId, new ArrayList<Integer>() );
return this.listMap.size();
}
This will add a new ArrayList<Integer> to the listMap.
Add numbers to a certain list
We now write a new method to add numbers to a certain list
public int addNumberToList(String listId, Integer number) {
this.listMap.get(listId).add(number);
return this.listMap.get(listId).size();
}
Calculate the average for a certain list
Now we can use the lists to calculate their average
public double averageForList(String listId){
double sum = 0;
double average = 0;
for (Integer number : this.listMap.get(listId) )
{
sum += number;
}
if (this.listMap.get(listId).size() != 0) average = sum / this.listMap.get(listId).size();
return average;
}
And that should be it.

Finding 'distance' between elements in an array

I'm trying to solve an auto-cipher and to find the key length i need to find the 'distance' between all elements in the cipher-text.
I've found the distances between all elements in the array however i now want some way to find the frequency of each jump.
So for example, if i had a string "ababbababba" and wanted to work with a's, the frequency of jumps of 1 is 2 and the frequency of jumps of 2 is 2.
for(int i = 1; i<cipher2.length(); i++ ){
if(cipher2Array[i] == 'f') {
arrayList.add(i);
int jumpDistance = arrayList.get(i) - arrayList.get(i-1);
}
}
So basically from here, with my jumpDistance variable, how would I something like
if(jumpDistance == theSameinAnyOtherPlaceOfArray) {
counter++;
}
And output a type of table with jumpSize, frequency
You would need a HashMap<Integer, Integer>. You can store the jumpSize as a key and the corresponding frequency as value.
Yet again if you want multiple characters to be eveluated at one go, you would need a nested Map ie - a map for each character Map<Character, Map<Integer, Integer>> as suggested by #SAM.
Map<Integer, Integer> counter = new HashMap<Integer, Integer>();
for(int i = 1; i<cipher2.length(); i++ ){
if(cipher2Array[i] == 'f') {
arrayList.add(i);
int jumpDistance = arrayList.get(i) - arrayList.get(i-1);
Integer freq = counter.get(jumpdistance);
freq = freq == null ? 1 : freq+1;
counter.put(jumpDistance, freq);
}
}

How would I set the max amount of times an int can appear from a random number generator?

Say if I randomly generated 30 numbers from 1 to 50 but for example I didn't want 4 to occur more than 3 times at most, or 23 to occur more than once. How would I go about doing this?
I would use a Map. If you haven't used a Map before, check this link out.
Then you could implement something like this:
Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>();
for(...)
{
//#Generate Random Number#//
Integer occur = occurrences.get(randNum);
occurrences.put(randNum, (occur == null) ? 1 : occur + 1);
if(occurrences.get(randNum) > occurrenceLimit)
{
//#Generate a different random number and try again#//
}
}
Here is one possible solution using pseudocode
//initialize a list
Collection numbers;
for i = some min value; i < desired max number; i++
numbers.add(i)
Integer grabRandomNumber()
{
//now generate a random INDEX based on the size of your collections list
index = randomNumber(0, numbers.size() - 1)
//Now go to that index and grab that number
numberYouWant = numbers.get(index)
//BUT you should remove the number you retrieved so the next time
//you try and grab a number you won't grab a duplicate
numbers.remove(index)
//then just return the number you got
return numberYouWant
}
Random rand = new Random();
List<int> randoms = new ArrayList<>();
for (int i = 0 ; i < 30 ; i++) {
int num = rand.nextInt(50) + 1;
if (num == 23 && randoms.contains(23)) {
i--;
break;
}
if (num == 4 && Collections.frequency(randoms, 4) >= 3) {
i--;
break;
}
randoms.add(num);
}
Method 1
(most basic, but inefficient)
You can use an integer array with the size of the bounds you are using for your integers (or a Hashanah with Integer to Integer for large ranges) and every time a number appears you increment the integer value.
Then when looping you check if the returned value has exceeded it's limit of uses and get another value and repeat.
Method 2
There is a second method which can be better than the first as when there is only one value possible out of 100 numbers the method could repeat many times before one result.
What you do is use a
HashMap of Integer to Integer.
You then put all possible values as keys into it with their limits of returns (and a flag for no limit) as the values.
You then generate a random number from 0 to the HashMap size - 1 and get the corresponding index in the keySet if the HashMap and decrement the value related to the key until it is 0 and then you remove the value.
Example:
HashMap map = new HashMap();
Random r = new Random();
while( map.size() > 0){
int index =r.nextInt (map.size());
int key = map.keySet().get(index);
map.put(key, map.get(key)-1);
if( map.get(key) == 0){
map.remove(key);
}
}
First of all, putting restrictions on this kind of thing somewhat defeats the whole definition of random.
That said, you can count the number of times each number is generated and check the count against whatever rules you need before returning the latest figure.

How to store number of elements exceeding the range of integers

I am given a problem in which I have to store a list of N numbers in an array and then sort it ,
and then I have to add the numbers at alternative positions and output the sum.
The problem is the constraint of N i.e 0 <= N <= 1011 so I have to declare the N as double type variable here is my code :
ArrayList<Double> myList = new ArrayList<Double>();
myList.add(number);
.....
Collections.sort(myList);
String tempNo = "";
for(double i = 0 ; i < myList.size() ; i=i+2){
tempNo = myStringWayToAdd(tempNo , myList(i)+""); // Since the sum will exceed the limit of double I have to add the numbers by help of Strings
}
But the problem is that the get(int) method takes an int not double. Is there any other way I can solve the problem? , and Is it even allowed to store number of elements that exceed int range?
Any help will be highly appreciated. Thank you in Advance.
Edit 1 :
I can use Strings instead of double in ArrayList and then add up the numbers but my problem is that i need to store N elements which can exceed the range of Integers
You could use LinkedList because it does not have a size limit (although odd things may begin to happen up there). You should also be able to use BigInteger for your numbers if the numbers themselves could get huge (you don't seem to state).
// LinkedList can hold more than Integer.MAX_VALUE elements,
List<BigInteger> myList = new LinkedList<>();
// Fill it with a few numbers.
Random r = new Random();
for (int i = 0; i < 1000; i++) {
myList.add(BigInteger.probablePrime(10, r));
}
// Sort it - not sure if Collections.sort can handle > Integer.MAX_VALUE elements but worth a try.
Collections.sort(myList);
// Start at 0.
BigInteger sum = BigInteger.ZERO;
// Add every other one.
boolean addIt = false;
for (BigInteger b : myList) {
if (addIt) {
sum = sum.add(b);
}
addIt = !addIt;
}
I am not sure if Collections.sort can handle a list of numbers that big, let alone whether it will succeed in sorting within the age of the universe.
You may prefer to consider a database but again you might even have probelms there with this many numbers.
Ah, I misunderstood the question. So we have to store something that is significantly larger than the capacity of int.
Well, we can do this by dividing and conquering the problem. Assuming this is theoretical and we have unlimited memory, we can create a SuperArrayList.
'Scuse my bad generics, no compiler.
public class SuperArrayList<E>() {
private ArrayList<ArrayList<E>> myList;
private int squareRoot;
private double capacity;
public SuperArrayList(double capacity) {
this.capacity = capacity;
squareRoot = Math.ceil(Math.sqrt(capacity)); //we create a 2d array that stores the capacity
myList = new ArrayList<ArrayList<E>>();
for(int i = 0; i < squareRoot; i++) {
myList.add(new ArrayList<E>());
}
}
public E get(double index) {
if(index >= capacity || index < 0) {
//throw an error
}
else {
return myList.get((int) capacity / squareRoot).get(capacity % squareRoot);
}
}
}
As an alternative to squareRoot, we can do maxValue and add additional arraylists of length maxvalue instead.
boolean add = true;
for (Double doubleNum : myList) {
if (add) {
tempNo = myStringWayToAdd(tempNo , doubleNum+"");
}
add = !add;
}
Using this way, you won't have to use index.

Categories

Resources