Collection Iteration not showing proper values? - java

I'm iterating through a simple Collection. I populate the Collection with random Integer objects, defined via the following:
Collection<Integer> treeSet = new TreeSet<>();
treeSet = createFilledCollection(10000, treeSet);
printContents(hashSet);
//populate the Collection
private Collection<Integer> createFilledCollection(long size, Collection<Integer> collection){
for(int i = 0 ; i < size; i++) {
Integer integer = (int)(Math.random() * 100);
collection.add(integer);
}
return collection;
}
Then I iterate through the contents of this Collection and print it's contents through the printContents(hashSet);
private void printContents(Collection<Integer> collection) {
StringJoiner joiner = new StringJoiner(",");
for(Integer i : collection) {
if(i > 500)
break;
System.out.println(i);
joiner.add(i.toString());
}
System.out.println(joiner.toString());
}
I'm expecting to see a random assortment of numbers
10 41 2 23 44 65 6... 19 11
(as I add random numbers through the createFilledCollection(Integer size, Collection collection) method. However, I get the following output:
0 1 2 3 4 5 6... 98 99
Why am I not seeing random numbers? (and yes, I checked to make sure I am not printing the iteration point)

That is because you are using TreeSet, The ordering of the elements is maintained by a set using their natural ordering whether or not an explicit comparator is provided.
Change TreeSet to like HashSet and you will get the desired output

Related

Finding mode for every window of size k in an array

Given an array of size n and k, how do you find the mode for every contiguous subarray of size k?
For example
arr = 1 2 2 6 6 1 1 7
k = 3
ans = 2 2 6 6 1 1
I was thinking of having a hashmap where the key is no and value is frequency, treemap where the key is freq and value is number, and having a queue to remove the first element when the size > k. Here the time complexity is o(nlog(n)). Can we do this in O(1)?.
This can be done in O(n) time
I was intrigued by this problem in part because, as I indicated in the comments, I felt certain that it could be done in O(n) time. I had some time over this past weekend, so I wrote up my solution to this problem.
Approach: Mode Frequencies
The basic concept is this: the mode of a collection of numbers is the number(s) which occur with the highest frequency within that set.
This means that whenever you add a number to the collection, if the number added was not already one of the mode-values then the frequency of the mode would not change. So with the collection (8 9 9) the mode-values are {9} and the mode-frequency is 2. If you add say a 5 to this collection ((8 9 9 5)) neither the mode-frequency nor the mode-values change. If instead you add an 8 to the collection ((8 9 9 8)) then the mode-values change to {9, 8} but the mode-frequency is still unchanged at 2. Finally, if you instead added a 9 to the collection ((8 9 9 9)), now the mode-frequency goes up by one.
Thus in all cases when you add a single number to the collection, the mode-frequency is either unchanged or goes up by only one. Likewise, when you remove a single number from the collection, the mode-frequency is either unchanged or goes down by at most one. So all incremental changes to the collection result in only two possible new mode-frequencies. This means that if we had all of the distinct numbers of the collection indexed by their frequencies, then we could always find the new Mode in a constant amount of time (i.e., O(1)).
To accomplish this I use a custom data structure ("ModeTracker") that has a multiset ("numFreqs") to store the distinct numbers of the collection along with their current frequency in the collection. This is implemented with a Dictionary<int, int> (I think that this is a Map in Java). Thus given a number, we can use this to find its current frequency within the collection in O(1).
This data structure also has an array of sets ("freqNums") that given a specific frequency will return all of the numbers that have that frequency in the current collection.
I have included the code for this data structure class below. Note that this is implemented in C# as I do not know Java well enough to implement it there, but I believe that a Java programmer should have no trouble translating it.
(pseudo)Code:
class ModeTracker
{
HashSet<int>[] freqNums; //numbers at each frequency
Dictionary<int, int> numFreqs; //frequencies for each number
int modeFreq_ = 0; //frequency of the current mode
public ModeTracker(int maxFrequency)
{
freqNums = new HashSet<int>[maxFrequency + 2];
// populate frequencies, so we dont have to check later
for (int i=0; i<maxFrequency+1; i++)
{
freqNums[i] = new HashSet<int>();
}
numFreqs = new Dictionary<int, int>();
}
public int Mode { get { return freqNums[modeFreq_].First(); } }
public void addNumber(int n)
{
int newFreq = adjustNumberCount(n, 1);
// new mode-frequency is one greater or the same
if (freqNums[modeFreq_+1].Count > 0) modeFreq_++;
}
public void removeNumber(int n)
{
int newFreq = adjustNumberCount(n, -1);
// new mode-frequency is the same or one less
if (freqNums[modeFreq_].Count == 0) modeFreq_--;
}
int adjustNumberCount(int num, int adjust)
{
// make sure we already have this number
if (!numFreqs.ContainsKey(num))
{
// add entries for it
numFreqs.Add(num, 0);
freqNums[0].Add(num);
}
// now adjust this number's frequency
int oldFreq = numFreqs[num];
int newFreq = oldFreq + adjust;
numFreqs[num] = newFreq;
// remove old freq for this number and and the new one
freqNums[oldFreq].Remove(num);
freqNums[newFreq].Add(num);
return newFreq;
}
}
Also, below is a small C# function that demonstrates how to use this datastructure to solve the problem originally posed in the question.
int[] ModesOfSubarrays(int[] arr, int subLen)
{
ModeTracker tracker = new ModeTracker(subLen);
int[] modes = new int[arr.Length - subLen + 1];
for (int i=0; i < arr.Length; i++)
{
//add every number into the tracker
tracker.addNumber(arr[i]);
if (i >= subLen)
{
// remove the number that just rotated out of the window
tracker.removeNumber(arr[i-subLen]);
}
if (i >= subLen - 1)
{
// add the new Mode to the output
modes[i - subLen + 1] = tracker.Mode;
}
}
return modes;
}
I have tested this and it does appear to work correctly for all of my tests.
Complexity Analysis
Going through the individual steps of the `ModesOfSubarrays()` function:
The new ModeTracker object is created in O(n) time or less.
The modes[] array is created in O(n) time.
The For(..) loops N times:
. 3a: the addNumber() function takes O(1) time
. 3b: the removeNumber() function takes O(1) time
. 3c: getting the new Mode takes O(1) time
So the total time is O(n) + O(n) + n*(O(1) + O(1) + O(1)) = O(n)
Please let me know of any questions that you might have about this code.

Out of Bound Error at arraylist in prefix average algorithm

java.lang.IndexOutOfBoundsException: error occurs when adding a single value to the first arrayList, in order to perform prefix averages as such that the value of A is computed by
id like to note that using arrays in this algorithm worked but when trying to switch to an arraylist does the issue occur.
Array A Contents of A[i]
A[0] (X[0])/1
A[1] (X[0]+X[1])/2
A[2] (X[0]+X[1]+X[2])/3
A[3] (X[0]+X[1]+X[2]+X[3])/4
A[4] (X[0]+X[1]+X[2]+X[3]+X[4])/5
A[5] (X[0]+X[1]+X[2]+X[3]+X[4]+X[5])/6
A[6] (X[0]+X[1]+X[2]+X[3]+X[4]+X[5]+X[6])/7
A[7] (X[0]+X[1]+X[2]+X[3]+X[4]+X[5]+X[6]+X[7])/8
A[8] (X[0]+X[1]+X[2]+X[3]+X[4]+X[5]+X[6]+X[7]+X[8])/9
A[9] (X[0]+X[1]+X[2]+X[3]+X[4]+X[5]+X[6]+X[7]+X[8]+X[9])/10
started off with a.get(i) = s/(i+1); that didn't help. then tried setting the contents of a[i] with the out come of s/(i+1) still no avail
public class prefixAverage{
public static void main(String args[]) {
ArrayList <Float> X = new ArrayList <Float>();
X.add(9f);
System.out.print(PrefixAverage(X));
}
public static ArrayList<Float> PrefixAverage(ArrayList<Float> X){
ArrayList <Float> a = new ArrayList <Float>();
float s = 0;
for (int i = 0; i<= X.size()-1;i++) {
s = s +X.get(i);
a.set(i,s/(i+1));
System.out.print(a.get(i)+", ");
}
return a;
}
}
I am expecting an increasing size average as the index of A increase
List::set sets an existing element to a new value. In your case, a is an empty list so you can't use that method (or you get an exception).
You probably meant to use a.add(i, value) instead, which will insert an element at the given index (and expand the list by one item).
In your case, you are inserting at index 0, then 1 etc., so you can simply use a.add(value).

How to split an amount of objects evenly over groups, given a maximum amount of objects per group (Java)

I am working on a school project in which I have an ArrayList with objects. I have to split these objects evenly over groups (other ArrayLists), with a maximum amount of objects per group(maximumGroupSize).
How do I split these objects so that they are evenely distributed over the groups, with the minimum amount of groups given the maximumGroupSize?
I have tried the following code:
public List<List<Object>> createGroups(List<Object> objects, int maximumGroupSize) {
float totalObjectCount = objects.size();
float maxGroupSize = maximumGroupSize;
List<List<Object>> groups = new ArrayList<>();
for (int i = 0; i < java.lang.Math.ceil(totalObjectCount / maximumGroupSize); i++){
List<Object> group = new ArrayList<>();
for (int j = (i*maximumGroupSize); j < maximumGroupSize*(i+1);j++){
if (j<objects.size()) {
group.add(objects.get(j));
}
}
groups.add(group);
}
return groups;
}
This will result in the first groups all having maximum capacity. But the last group that is created will contain the "leftovers".
So if I have a total list of 18 objects and maximumGroupSize = 8, it will result in two groups of 8 objects and one of 2 objects.
If possible, I would like to have the size of the groups as close to each other as possible.
So that would output three lists of 6 with the above input.
I am working in Java, so I need a way to do it in Java. Code would be great, but also a step by step way to split would be okay so I could create the code myself.
Since you have now provided the code that you tried, here is my solution which I was not posting earlier as you had shown no attempt:-
public static void main(String[] args) {
List<Integer> list = IntStream.range(10, 20)
.boxed()
.collect(Collectors.toList());
List<Integer> groups[] = createGroups(list, 4);
for (List<Integer> group : groups) {
System.out.println(group);
}
}
public static List<Integer>[] createGroups(List<Integer> list, int maximumPerGroup) {
int numberOfGroups = list.size() / maximumPerGroup;
if (list.size() % maximumPerGroup > 0) numberOfGroups++;
List<Integer> groups[] = new ArrayList[numberOfGroups];
for (int i = 0; i < list.size(); i++) {
if (groups[i % numberOfGroups] == null) groups[i % list.size()] = new ArrayList<>();
groups[i % numberOfGroups].add(list.get(i));
}
return groups;
}
Output
[10, 13, 16, 19]
[11, 14, 17]
[12, 15, 18]
If you're given the maximum group size allowed for the split groups, then you can use this to figure out the minimum number of groups.
This can be done by using the length of the original ArrayList. Divide the number of objects in the original list by the maximum group size, and take the ceiling of this number to get your minimum number of groups.
So for example if you're given an ArrayList of Objects that has 11 Objects in it, and your maximum group size is 2, then your minimum number of groups is 6.
From this you can now create the required number of ArrayLists required. Once you've got these ArrayLists it should be pretty easy to split the original list into these ones.

how to create a Java List of two integers

Hello I am new to java and I am trying to create a list like
List<Int, Int> list = new List<Int, Int>();
the first int is the value and the second int is the finished time. I want to be able to read from a file and save in my list, So can I later get the finished time or value list in a sorted way. I am going to ue these two list together so when the first one is sorted the second one also needs to be sorted accordingly.
If I use HashMap I cant add duplicate values, can someone help me please?
I tried with TreeMap but it also didnt work.
You should create a class to wrap your values. Something like:
public class IntPair {
public int value;
public int time;
}
should do. You can then add a constructor, a compare method for sorting, and whatever other functionality you need.
Create the list as follows:
List<IntPair> list = new ArrayList<>();
Using java inbuilt Pair class. ArrayList or any List of pairs can be constructed. you need to import javafx.util.pair for that. Similarly for 3 values. Use java's Triplet class.
eg: Pair p=new Pair(1, 2);
ArrayList or any List of these pairs can be constructed easily now
The 'lazy' way you could create an ArrayList<Integer[]> at each index you add an array of 2 places holding the value and the time ex new Integer[]{val,time} and then you can sort the arraylist using the Collection.sort and with the help of a Comparator
Here is a small example :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ArrayList<Integer[]> values = new ArrayList<>();
Random rand = new Random();
// just for testing I add random values but you
// should add your values you read from your file
for (int i = 0; i < 10; i++) {
values.add(new Integer[] { rand.nextInt(100), rand.nextInt(100) });
System.out.println(values.get(i)[0] + "\t" + values.get(i)[1]);
}
// Let's sort our ArrayList looking at the first index of each array
// which holds the value
Collections.sort(values, new Comparator<Integer[]>() {
public int compare(Integer[] array1, Integer[] array2) {
return array1[0].compareTo(array2[0]);
}
});
// Print the results
System.out.println();
System.out.println();
for (int i = 0; i < 10; i++) {
System.out.println(values.get(i)[0] + "\t" + values.get(i)[1]);
}
}
}
Output :
82 21
3 54
60 73
14 35
45 30
16 30
8 19
62 43
67 51
7 34
3 54
7 34
8 19
14 35
16 30
45 30
60 73
62 43
67 51
82 21

How to get 100 random elements from HashSet in Java?

I have a HashSet in which I have 10000 elements. I want to extract random 100 elements from that HashSet. So I thought I can use shuffle on the set but it doesn't work.
Set<String> users = new HashSet<String>();
// for randomness, but this doesn't work
Collections.shuffle(users, new Random(System.nanoTime()));
// and use for loop to get 100 elements
I cannot use shuffle now, is there any other best way to get 100 random elements from HashSet in Java?
Without building a new list, you can implement the following algorithm:
n = 100
d = 10000 # length(users)
for user in users:
generate a random number p between 0 and 1
if p <= n / d:
select user
n -= 1
d -= 1
As you iterate through the list, you decrease the probability of
future elements from being chosen by decreasing n, but at the the
same time increase the probability by decreasing d. Initially,
you would have a 100/10000 chance of choosing the first element.
If you decide to take that element, you would have a 99/9999 chance
of choosing the second element; if you don't take the first one, you'll
have a slightly better 100/9999 chance of picking the second element. The math works out so that in the end, every element has a 100/10000 chance of being selected for the output.
Shuffling the collection implies that there is some defined order of elements within, so elements can be reordered. HashSet is not an ordered collection as there is no order of elements inside (or rather details of the ordering are not exposed to the user). Therefore implementation wise it's does not makes much sense to shuffle HashSet.
What you can do is add all elements from your set to the ArrayList, shuffle it and get your results.
List<String> usersList = new ArrayList<String>(users);
Collections.shuffle(usersList);
// get 100 elements out of the list
The java.lang.HashSet has an order so you can't shuffle Sets. If you must use Sets you might iterate over the Set and stop on a random position.
Pseudocode:
Set randomUsers = new HashSet<String>();
Random r = new Random();
Iterator it = users.iterator();
numUsersNeeded = 100;
numUsersLeft = users.size();
while (it.hasNext() && randomUsers.size() < 100) {
String user = it.next();
double prop = (double)numUsersNeeded / numUsersLeft;
--numUsersLeft;
if (prop > r.nextDouble() && randomUsers.add(user)) {
--numUsersNeeded;
}
}
You might repeat this because there is no garantiy that you fetch 100 elements.
If memory is no issue you can create an array and pick 100 random elements:
Pseudocode II:
Object userArray[] = user.toArray();
Set<String> randoms = new HashSet<String>();
while(randoms.size() != 100) {
int randomUser = userArray[new Random().nexInt(10000)];
randoms.add(randomUser);
}

Categories