ArrayList of HashSets iterating over indexes I don't specify? - java

isPrime() checks if a number is prime, and getPrimes(int upper) gets all primes up to and including upper. I want sievePrimeFactorSets to make a HashSet of all the prime factors (no repeats) of each number, and to store that HashSet at the given value, e.g. the HashSet at primeFactors.get(20) = [2,5].
Right now it adds every prime to every value, so primeFactors.get(20) = [2,3,5,7,11,13,etc]. Why is this happening?
public ArrayList<HashSet<Integer>> sievePrimeFactorSets(int upper)
{
ArrayList<HashSet<Integer>> primeFactors = new ArrayList<HashSet<Integer>>();
HashSet<Integer> empty = new HashSet<Integer>();
for (int i = 0; i <= upper; i++)
{
primeFactors.add(empty);
}
ArrayList<Integer> primes = getPrimes(upper);
for (Integer p : primes)
{
for (int j = p; j <= upper; j+=p)
{
primeFactors.get(j).add(p);
}
}
return primeFactors;
}
public ArrayList<Integer> getPrimes (int upper)
{
ArrayList<Integer> primes = new ArrayList<Integer>();
primes.add(2);
for (int i = 3; i <= upper; i++)
{
if (isPrime(i))
{
primes.add(i);
}
}
return primes;
}

This line:
primeFactors.add(empty);
adds the same empty hash set to each element of the array. So every element shares the same hash set and the changes you think you are making to one are actually made to all elements.
Just replace with:
primeFactors.add(new HashSet<>());

Related

Java - Find maximum number of duplicates within an array

I am utilizing a HashSet for finding the maximum number of duplicates of a value in a sorted Integer array. But my algorithm doesn't seem to work, not returning the desired results.
Set variables storing the number of duplicates found (0), and the maximum number of duplicates (0).
Set a HashSet that stores the unique values of an array.
Sort the array to be ready for comparison.
Loop through each value of the array
If the HashSet of unique values contains the current value:
Increment the duplicate Count
If the currentValue is not equal to the previous value:
If the duplicateCount is greater than the maximum Count:
maximumCount becomes duplicateCount
Reset duplicateCount to 0
Java Code:
HashSet<Integer> uniqueValues = new HashSet<Integer>(valueSequenceList);
int duplicateCount = 0;
int maxCount = 0;
Arrays.sort(valueSequence);
for (int i = 0; i < valueSequence.length; i++)
{
if (uniqueValues.contains(valueSequence[i]))
{
duplicateCount++;
}
if (i > 0 && valueSequence[i] != valueSequence[i-1])
{
if (duplicateCount > maxCount)
{
maxCount = duplicateCount;
duplicateCount = 0;
}
}
}
Example:
Input: [4, 4, 10, 4, 10]
Output: 4 Duplicates (There are supposed to be a maximum of 3 duplicates - Total number of values that are the same).
This is the Element Distinctness Problem - which is explained with details in the thread: Find duplicates in an array.
The mentiones thread discusses solutions to the problem, and shows lower bounds as well (cannot be done better than O(nlogn) without using a hash table.
So, if your data is not sorted - you could sort and iterate (as follows), or use a hash set - and then you don't need to sort the array.
If you first sort the array, or the array is already sorted, a single iteration will do:
Single iteration on a sorted array:
if (arr == null || arr.length == 0) return 0;
int last = arr[0];
int numDupes = 1;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == last) numDupes++;
last = arr[i];
}
Using a HashSet (no need to sort):
if (arr == null) return 0;
Set<Integer> set = new HashSet<>();
int numDupes = 0;
for (int x : arr) {
if (set.contains(x)) numDupes++;
set.add(x);
}
If you are looking for the maximal number some element repeats (and not total number of repeats), you can use the same approach but slightly different:
Hashing solution - use a histogram:
Map<Integer,Integer> histogram = new HashMap<>();
for (int x : arr) {
if (!histogram.containsKey(x)) histogram.put(x,1);
else histogram.put(x,histogram.get(x) + 1);
}
int max = 0;
for (int x : histogram.values) max = max > x ? max : x;
return max;
Sorted array solution:
if (arr == null || arr.length == 0) return 0;
int last = arr[0];
int max = 0;
int currNumDupes = 1;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == last) currNumDupes++;
else {
max = max > currNumDupes ? max : currNumDupes;
currNumDupes = 1;
}
last = arr[i];
}
max = max > currNumDupes ? max : currNumDupes; //if the most dupes is from the highest element
check the following code which returns the max count of duplicates
public static void main(String args[]) {
int[] inputArray = { 4, 4, 10, 4, 10 };
Map<Integer, Integer> hMap = new HashMap<Integer, Integer>();
HashSet<Integer> hSet = new HashSet<Integer>();
for (int i : inputArray) {
if (hSet.add(i)) {
hMap.put(i, 1);
} else {
hMap.put(i, hMap.get(i) + 1);
}
}
Iterator<Integer> iter = hMap.values().iterator();
int temp = 0;
while (iter.hasNext()) {
int max = iter.next();
if (max > temp) {
temp = max;
}
}
System.out.println(temp);
}
Suggestion:
You could use a simple Map<Integer, Integer> where the key is the item value, and the value is the count of that item.
This would make the code simple - no need to sort:
Map<Integer, Integer> count = new HashMap<Integer, Integer>();
for (Integer item : list){
if (count.containsKey(item)){
// increate count
count.put(item, count.get(key) + 1);
} else {
// no item yet - set count to 1
count.put(item, 1);
}
}
You could now use something like Collections.max to find the maximum Integer value on count.values() - or even write a Comparator<Entry<Integer, Integer>> for the entries to find the maximal Map.Entry<Integer, Integer> from count.entrySet() (preferable, can be used with Collections.max).
Note: You could use something like MutableInt (Apache commons) or even AtomicInt for mutable map values. I haven't tested the differences but it may be faster.
EDIT : I'm assuming (based on your code) that the goal is to find the number of appearances of the number that appears the most in the array. Calling it "maximum number of duplicates" is misleading.
First of all, the HashSet is useless. You add all the elements to it up front, which means uniqueValues.contains(valueSequence[i]) is always true.
Now, you only want to increment the duplicateCount if you still haven't moved to the next element :
for (int i = 0; i < valueSequence.length; i++)
{
if (i == 0 || valueSequence[i] == valueSequence[i-1])
{
duplicateCount++;
}
else
{
if (duplicateCount > maxCount)
{
maxCount = duplicateCount;
}
duplicateCount = 1; // another small fix
}
}
if (duplicateCount > maxCount)
maxCount = duplicateCount;
}
If the goal is to find the number of duplicates, you can do it without any loop (since the number of duplicates is the total number of elements minus the number of unique elements) :
HashSet<Integer> uniqueValues = new HashSet<Integer>(valueSequenceList);
int duplicateCount = valueSequenceList.size() - uniqueValues.size();
String[] Csssplit = Css.split("====");
HashMap<String,Integer> Spancsslist = new HashMap<String,Integer>();
for(int c=0;c<Csssplit.length;c++){
Css = Csssplit[c];
//System.out.println("css::"+Css);
int count = Spancsslist.getOrDefault(Css, 0);
Spancsslist.put(Css,count+1);
}
if(Spancsslist.size()==0){ continue; }
Spancsslist = Spancsslist.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,LinkedHashMap::new));
Css = Spancsslist.keySet().stream().findFirst().get();
using Integer.MIN_VALUE to find max array, then count duplicate max int array.
public static int main(int[] ar) {
int count = 0;
int max = Integer.MIN_VALUE;
int lastMax = 0;
for(int i = 0; i < ar.length; i++) {
if(ar[i] > max) {
max = ar[i];
if(lastMax != max){
count = 0;
}
lastMax = max;
}
if(ar[i] == max) {
count += 1;
}
}
return count;
}

ArrayList randomize with index change for all elements

How can I randomize arrayList
so that old index must not be the same as new index for all elements
for example
with a list with 3 items
after arrayList randomize
old index<->new index
1<-->2 <--different
2<-->1 <--different
3<-->3 <--same is not allowed
I want to make sure it will be
1<-->3 <--different
2<-->1 <--different
3<-->2 <--different
Collections.shuffle(List<?> list)
This should work with Lists which don't contain null values:
static <T> void shuffleList(List<T> list) {
List<T> temp = new ArrayList<T>(list);
Random rand = new Random();
for (int i = 0; i < list.size(); i++) {
int newPos = rand.nextInt(list.size());
while (newPos == i||temp.get(newPos)==null) {
newPos = rand.nextInt(list.size());
}
list.set(i, temp.get(newPos));
temp.set(newPos,null);
}
}
For list with null values:
static <T> void shuffleList(List<T> list) {
List<T> temp = new ArrayList<T>(list);
Integer [] indexes=new Integer[list.size()];
for (int i=0;i<list.size();i++){
indexes[i]=i;
}
Random rand = new Random();
for (int i = 0; i < list.size(); i++) {
int newPos = rand.nextInt(list.size());
while (newPos == i||indexes[newPos]==null) {
newPos = rand.nextInt(list.size());
}
list.set(i, temp.get(newPos));
indexes[newPos]=null;
}
}
That's something you have to implement yourself.
The shuffle is probably a series of random swaps (e.g. swap 1 -> 4,
swap 3 -> 2).
Keep track of each element's new position (e.g. 4 3 2
1 5 for a list with 5 elements and the above shuffle operations).
If any element is still at it's old place (5 in that example),
keep on shuffling.
Sounds like fun.
var numExist = [];
while(numExist.length!=array.length){
var randomizer = new Random();
int i =0;
var num = randomizer.nextInt(array.length);
if(!numExist.contains(num)){
array[i]=array[num];
numExist.add(num);
i++;
}
}
The following is a variation of Fisher-Yates which caters to the possibility that at least one item will remain in its original position.
The current Collections.shuffle() does not perform a complete randomization of the list.
public static void shuffle(List<Integer> list) {
Random r = new Random();
int size = list.size();
boolean flag = true;
for (int i = size - 1; i >= 0 && flag; i--) {
int pos = r.nextInt(i + 1);
if (list.get(i) == pos) {
if (i == 0) {
flag = false;
break;
}
// counter the upcoming decrement by incrementing i
i++;
continue;
}
int temp = list.get(i);
list.set(i, list.get(pos));
list.set(pos, temp);
}
// At this juncture, list.get(0) points to itself so choose a random candidate
// and swap them.
if (!flag) {
int pos = r.nextInt(size - 1) + 1;
int temp = list.get(0);
list.set(0, list.get(pos));
list.set(pos, list.get(0));
}
}
There may still be eventual problems but I used the following code to test the
shuffle with no problems detected.
for (int k = 0; k < 100000; k++) {
List<Integer> list =
IntStream.range(0, 52).boxed().collect(Collectors.toList());
System.out.println("Test run #" + k);
// Collections.shuffle(list);
shuffle(list);
for (int i = 0; i < list.size(); i++) {
if (i == list.get(i)) {
System.out.printf("Oops! List.get(%d) == %d%n", list.get(i), i);
}
}
}

Get indices of n maximums in java array

I have an array of size 1000. How can I find the indices (indexes) of the five maximum elements?
An example with setup code and my attempt are displayed below:
Random rand = new Random();
int[] myArray = new int[1000];
int[] maxIndices = new int[5];
int[] maxValues = new int[5];
for (int i = 0; i < myArray.length; i++) {
myArray[i] = rand.nextInt();
}
for (int i = 0; i < 5; i++) {
maxIndices[i] = i;
maxValues[i] = myArray[i];
}
for (int i = 0; i < maxIndices.length; i++) {
for (int j = 0; j < myArray.length; j++) {
if (myArray[j] > maxValues[i]) {
maxIndices[i] = j;
maxValues[i] = myArray[j];
}
}
}
for (int i = 0; i < maxIndices.length; i++) {
System.out.println("Index: " + maxIndices[i]);
}
I know the problem is that it is constantly assigning the highest maximum value to all the maximum elements. I am unsure how to remedy this because I have to preserve the values and the indices of myArray.
I don't think sorting is an option because I need to preserve the indices. In fact, it is the indices that I need specifically.
Sorry to answer this old question but I am missing an implementation which has all following properties:
Easy to read
Performant
Handling of multiple same values
Therefore I implemented it:
private int[] getBestKIndices(float[] array, int num) {
//create sort able array with index and value pair
IndexValuePair[] pairs = new IndexValuePair[array.length];
for (int i = 0; i < array.length; i++) {
pairs[i] = new IndexValuePair(i, array[i]);
}
//sort
Arrays.sort(pairs, new Comparator<IndexValuePair>() {
public int compare(IndexValuePair o1, IndexValuePair o2) {
return Float.compare(o2.value, o1.value);
}
});
//extract the indices
int[] result = new int[num];
for (int i = 0; i < num; i++) {
result[i] = pairs[i].index;
}
return result;
}
private class IndexValuePair {
private int index;
private float value;
public IndexValuePair(int index, float value) {
this.index = index;
this.value = value;
}
}
Sorting is an option, at the expense of extra memory. Consider the following algorithm.
1. Allocate additional array and copy into - O(n)
2. Sort additional array - O(n lg n)
3. Lop off the top k elements (in this case 5) - O(n), since k could be up to n
4. Iterate over the original array - O(n)
4.a search the top k elements for to see if they contain the current element - O(lg n)
So it step 4 is (n * lg n), just like the sort. The entire algorithm is n lg n, and is very simple to code.
Here's a quick and dirty example. There may be bugs in it, and obviously null checking and the like come into play.
import java.util.Arrays;
class ArrayTest {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
int[] indexes = indexesOfTopElements(arr,3);
for(int i = 0; i < indexes.length; i++) {
int index = indexes[i];
System.out.println(index + " " + arr[index]);
}
}
static int[] indexesOfTopElements(int[] orig, int nummax) {
int[] copy = Arrays.copyOf(orig,orig.length);
Arrays.sort(copy);
int[] honey = Arrays.copyOfRange(copy,copy.length - nummax, copy.length);
int[] result = new int[nummax];
int resultPos = 0;
for(int i = 0; i < orig.length; i++) {
int onTrial = orig[i];
int index = Arrays.binarySearch(honey,onTrial);
if(index < 0) continue;
result[resultPos++] = i;
}
return result;
}
}
There are other things you can do to reduce the overhead of this operation. For example instead of sorting, you could opt to use a queue that just tracks the largest 5. Being ints they values would probably have to be boxed to be added to a collection (unless you rolled your own) which adds to overhead significantly.
a bit late in answering, you could also use this function that I wrote:
/**
* Return the indexes correspond to the top-k largest in an array.
*/
public static int[] maxKIndex(double[] array, int top_k) {
double[] max = new double[top_k];
int[] maxIndex = new int[top_k];
Arrays.fill(max, Double.NEGATIVE_INFINITY);
Arrays.fill(maxIndex, -1);
top: for(int i = 0; i < array.length; i++) {
for(int j = 0; j < top_k; j++) {
if(array[i] > max[j]) {
for(int x = top_k - 1; x > j; x--) {
maxIndex[x] = maxIndex[x-1]; max[x] = max[x-1];
}
maxIndex[j] = i; max[j] = array[i];
continue top;
}
}
}
return maxIndex;
}
My quick and a bit "think outside the box" idea would be to use the EvictingQueue that holds an maximum of 5 elements. You'd had to pre-fill it with the first five elements from your array (do it in a ascending order, so the first element you add is the lowest from the five).
Than you have to iterate through the array and add a new element to the queue whenever the current value is greater than the lowest value in the queue. To remember the indexes, create a wrapper object (a value/index pair).
After iterating through the whole array, you have your five maximum value/index pairs in the queue (in descending order).
It's a O(n) solution.
Arrays.sort(myArray), then take the final 5 elements.
Sort a copy if you want to preserve the original order.
If you want the indices, there isn't a quick-and-dirty solution as there would be in python or some other languages. You sort and scan, but that's ugly.
Or you could go objecty - this is java, after all.
Make an ArrayMaxFilter object. It'll have a private class ArrayElement, which consists of an index and a value and has a natural ordering by value. It'll have a method which takes a pair of ints, index and value, creates an ArrayElement of them, and drops them into a priority queue of length 5. (or however many you want to find). Submit each index/value pair from the array, then report out the values remaining in the queue.
(yes, a priority queue traditionally keeps the lowest values, but you can flip this in your implementation)
Here is my solution. Create a class that pairs an indice with a value:
public class IndiceValuePair{
private int indice;
private int value;
public IndiceValuePair(int ind, int val){
indice = ind;
value = val;
}
public int getIndice(){
return indice;
}
public int getValue(){
return value;
}
}
and then use this class in your main method:
public static void main(String[] args){
Random rand = new Random();
int[] myArray = new int[10];
IndiceValuePair[] pairs = new IndiceValuePair[5];
System.out.println("Here are the indices and their values:");
for(int i = 0; i < myArray.length; i++) {
myArray[i] = rand.nextInt(100);
System.out.println(i+ ": " + myArray[i]);
for(int j = 0; j < pairs.length; j++){
//for the first five entries
if(pairs[j] == null){
pairs[j] = new IndiceValuePair(i, myArray[i]);
break;
}
else if(pairs[j].getValue() < myArray[i]){
//inserts the new pair into its correct spot
for(int k = 4; k > j; k--){
pairs[k] = pairs [k-1];
}
pairs[j] = new IndiceValuePair(i, myArray[i]);
break;
}
}
}
System.out.println("\n5 Max indices and their values");
for(int i = 0; i < pairs.length; i++){
System.out.println(pairs[i].getIndice() + ": " + pairs[i].getValue());
}
}
and example output from a run:
Here are the indices and their values:
0: 13
1: 71
2: 45
3: 38
4: 43
5: 9
6: 4
7: 5
8: 59
9: 60
5 Max indices and their values
1: 71
9: 60
8: 59
2: 45
4: 43
The example I provided only generates ten ints with a value between 0 and 99 just so that I could see that it worked. You can easily change this to fit 1000 values of any size. Also, rather than run 3 separate for loops, I checked to see if the newest value I add is a max value right after I add to to myArray. Give it a run and see if it works for you

Finding modes an an array

Does anyone know how to find the modes in an array when there are more then one mode? I have this code that finds one mode. But I'm dealing with an array which has more than one mode, a multimodal array and I have to print each mode exactly once. Here is my code, can someone help me out? Thanks.
public static int mode(int a[])
{
int maxValue=0, maxCount=0;
for (int i = 0; i < a.length; ++i)
{
int count = 0;
for (int j = 0; j < a.length; ++j)
{
if (a[j] == a[i]) ++count;
}
if (count > maxCount)
{
maxCount = count;
maxValue = a[i];
}
}
return maxCount;
}
public static Integer[] modes(int a[])
{
List<Integer> modes = new ArrayList<Integer>();
int maxCount=0;
for (int i = 0; i < a.length; ++i)
{
int count = 0;
for(int j = 0; j < a.length; ++j)
{
if (a[j] == a[i]) ++count;
}
if (count > maxCount)
{
maxCount = count;
modes.clear();
modes.add(a[i]);
}
else if (count == maxCount)
{
modes.add(a[i]);
}
}
return modes.toArray(new Integer[modes.size()]);
}
Since your elements will be between 10 and 1000, you can use a Counter array. In this Counter array, you can store the counts of the value of the a[i] element. I think you can understand this better in code:
public static List<Integer> mode(int[] a) {
List<Integer> lstMode = new ArrayList<Integer>();
final int MAX_RANGE = 1001;
int[] counterArray = new int[MAX_RANGE]; //can be improved with some maths :)!
//setting the counts for the counter array.
for (int x : a) {
counterArray[x]++;
}
//finding the max value (mode).
int maxCount = counterArray[0];
for(int i = 0; i < MAX_RANGE; i++) {
if (maxCount < counterArray[i]) {
maxCount = counterArray[i];
}
}
//getting all the max values
for(int i = 0; i < MAX_RANGE; i++) {
if (maxCount == counterArray[i]) {
lstMode.add(new Integer(i));
}
}
return lstMode;
}
If your input will have elements outside of 1000, you can look for the Map answer (like in other posts).
We should do this the easy way and utilize a Map data structure in the following format:
Map<Integer,Integer>
And then keep a running total, afterwards you iterate over the keyset and pull the highest value(s) from the Map.
If you want to stay with the List implementation you can do the following to remove dupes:
Set s = new HashSet(list);
list = new ArrayList(s);
One approach is to run (approximately) your current code twice: the first time, find maxCount, and the second time, print out each value that occurs maxCount times. (You'll need to make some modifications in order to print each mode only once, instead of printing it maxCount times.)
Instead of having a single maxValue, store the modes in an ArrayList<Integer>.
if (count == maxCount)
{
modes.add(a[i]);
}
else if (count > maxCount)
{
modes.clear(); // discard all the old modes
modes.add(a[i]);
maxCount = count;
}
and start with j = i instead of j = 0.
Since your array values only range from [10,1000], you could use a Map<Integer,Integer> to store a mapping between each discovered array value (map key) and its count (map value). A HashMap would work very well here.
To increment the count:
int count = (map.contains(a[i]) ? map.get(a[i]) : 1;
map.put(a[i],count);
Continue to track the max count like you already do, and at the end, just iterate over the map and collect all map keys with a map value equal to the max count.

Finding the mode of an array

Ok so I am stuck once again here is what I have
public static int mode(int[][] arr) {
List<Integer> list = new ArrayList<Integer>();
List<Integer> Mode = new ArrayList<Integer>();
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
list.add(arr[i][j]);
}
}
for(int i = 0; i < list.size(); i ++) {
Mode.add((Mode.indexOf(i)+1));
}
System.out.println(Mode);
return 0;
}
What I am trying to do is in order to find the mathematical mode of this array what I intend to do is for every number I encounter in the array increment the corresponding index by 1 eventually ending up with a new array with "tally" marks in the corresponding indexes, I am not sure } am going about this in the right way I need a dynamic array I assume in order to reach any number that may be encountered so one that can grow to whatever size I need, if my code is complete gibberish feel free to criticize at will :)
Have you considered using a Map instead of a List? That way you can eliminate the ugly indexOf call, and just refer to each instance of the elements by their value, not by doing a linear search each time. Then, all you have to do is find the key with the highest value in your map.
public static Set<Double> getMode(double[] data) {
if (data.length == 0) {
return new TreeSet<>();
}
TreeMap<Double, Integer> map = new TreeMap<>(); //Map Keys are array values and Map Values are how many times each key appears in the array
for (int index = 0; index != data.length; ++index) {
double value = data[index];
if (!map.containsKey(value)) {
map.put(value, 1); //first time, put one
}
else {
map.put(value, map.get(value) + 1); //seen it again increment count
}
}
Set<Double> modes = new TreeSet<>(); //result set of modes, min to max sorted
int maxCount = 1;
Iterator<Integer> modeApperance = map.values().iterator();
while (modeApperance.hasNext()) {
maxCount = Math.max(maxCount, modeApperance.next()); //go through all the value counts
}
for (double key : map.keySet()) {
if (map.get(key) == maxCount) { //if this key's value is max
modes.add(key); //get it
}
}
return modes;
}

Categories

Resources