Using a LinkedHashSet to store random numbers but has duplicates - java

I have an app that generates a random arithmetic expression. It then generates a correct answer in a random position (tag) and three subsequent incorrect answers allowing the user to choose.
I originally went with an ArrayList but it provides duplicates. I then converted the ArrayList contents in the for loop to a Set and it still produced duplicates. I then changed the initial ArrayList to a LinkedHashSet and alas, still duplicates. i'm thinking it might be the placement in my for loop but I've tried messing around with position and I either encounter duplicates or Index problems.
I don't want to use Java 8's:List<String> deDupStringList3 = strList.stream().distinct().collect(Collectors.toList()); as it's API/Version specific.
For Loop Code:
List<Integer> answers = new ArrayList<>(new HashSet<Integer>(5));
answers.clear();
int incorrectAnswer;
for (int i = 0; i < 4; i++) {
if (i == locCorrectAnswer) {
answers.add(value);
} else {
if (operator == '+') {
incorrectAnswer = value + rand.nextInt(10) + 1;
} else {
incorrectAnswer = value - rand.nextInt(10) + 1;
}
while (incorrectAnswer == value) {
if (operator == '+') {
incorrectAnswer = value + rand.nextInt(10) + 1;
} else {
incorrectAnswer = value - rand.nextInt(10) + 1;
}
}
answers.add(incorrectAnswer);
}
}
For Loop code (with ArrayList and conversion to Set):
ArrayList <Integer> answers;
Set<Integer> s = new LinkedHashSet<>(answers);
int incorrectAnswer;
for (int i = 0; i < 4; i++) {
if (i == locCorrectAnswer) {
answers.add(value);
} else {
if (operator == '+') {
incorrectAnswer = value + rand.nextInt(10) + 1;
} else {
incorrectAnswer = value - rand.nextInt(10) + 1;
}
while (incorrectAnswer == value) {
if (operator == '+') {
incorrectAnswer = value + rand.nextInt(10) + 1;
} else {
incorrectAnswer = value - rand.nextInt(10) + 1;
}
}
answers.add(incorrectAnswer);
}
s.addAll(answers);
answers.clear();
answers.addAll(s);
}
I'm sure its a simple error but I can't see it.

You can also try the following.
Set<Integer> s = new HashSet<>();
//correct value
s.add(value);
while (s.size() < 4)
{
//incorrect value
s.add( value + rand.nextInt(10) + 1);
}
List<Integer> answers = new ArrayList<>(s);
//shuffle
Collections.shuffle(answers);

Just create your Set of answers like this:
Set<String> answers = new LinkedHashSet<String>();
Now every value can be there just 1 time. It can be added without getting an error but it will be only one time in the list.
And you can still iterate/loop through it.

You're still calling answers.addAll(s) in the loop. While there won't be any duplicates in s in any given iteration, you will still get duplicates from different iterations.
Since you don't want any duplicates, there's no reason to use Lists in the first place. Any Set will remove duplicates, and LinkedHashSet will preserve insertion order.

Related

Code Not Correctly Finding The Most Common Element In Int Array?

I am using this method with the intentions of finding the most common element in an array. It works most of the time but for some reason it doesn't always work. I would also like it to be able to store if there are 2 numbers tied for most common but I am unsure how to do so.
Here is the code for the method: (The variable size is the size of the array)
public static int mostCommon(int size) {
int mostCommon = 0, mostCommonCount = 0, currentCount = 0;
for (int i = 1; i < size; i++) {
if (array[i - 1] == array[i]) {
currentCount++;
if (currentCount > mostCommonCount) {
mostCommonCount = currentCount;
mostCommon = array[i];
}
}
else
currentCount = 0;
}
return mostCommon;
}
This code is in the main and prints out the most common element:
if (mostCommon(size) == 0)
System.out.println("\nAll Elements In Your Array Occur Equally");
else
System.out.println("\nThe Most Common Element In Your Array Is: " + mostCommon(size));
I would really appreciate the help. Thanks!
Guessing this is irrelevant now but thought I would answer anyway.
I don't fully understand why you would pass the size of the array in but not the array itself, anyway, I have a solution, slightly modified from your method signature but if it is still needed then it can be modified to suit your exact situation.
public static Set<Integer> mostCommon()
{
int[] array = new int[] {1,2,3,4,5,5,4,3,4};
Map<Integer, Integer> counts = new HashMap<Integer,Integer>();
Set<Integer> highestCount = new TreeSet<Integer>();
//loop through the array to count common values
for(int numInArray : array)
{
//if number in array already been seen
if(counts.containsKey(numInArray))
{
counts.put(numInArray, counts.get(numInArray)+1);
}
//else set it at one
else
{
counts.put(numInArray, 1);
}
}
//loop through map to count highest occurences
int maxValue = 0;
int maxKey = 0;
for(Integer mapKey : counts.keySet())
{
int value = counts.get(mapKey);
//if value is greater than maxValue then set maxVale=value, also clear highestCount as they are lower now
if(value > maxValue)
{
highestCount.clear();
maxValue = value;
maxKey = mapKey;
}
//if value is the same as maxValue then store it in list, this will allow us to get two of the same max occurences
else if(value == maxValue)
{
highestCount.add(mapKey);
}
}
highestCount.add(maxKey);
System.out.println("counts " + counts);
System.out.println("final answer " + highestCount);
return highestCount;
}
I have tested various values in the array and it seems to work for all I tried.
This is by no means the most efficient method it is just a solution that works.
edit: Seen your other question and the code you posted that was this method and yours works much better than this answer
You can get logic by this solution and language use to solve this problem is SWIFT 4.2
var arrColor = ["red","green","blue","green","red","green","blue","green","red","green","blue","green","blue","green","red","green","blue","blue","green","red","green","blue","blue","blue","blue","blue"]
func mostCommonArray(array:[String])->[String]{
var commonArr = [String]()
var dictColor = [String:Int]()
for color in array{
if let count = dictColor[color]{
dictColor[color] = count + 1
}
else{
dictColor[color] = 1
}
}
let highestValue = dictColor.values.max()
for (color,count) in dictColor{
if dictColor[color] == highestValue{
commonArr.append(color)
}
}
return commonArr
}

Java - Arrays - checking for duplicates in same input

I'm trying to get the secret code from 1 - 40, not to repeat any numbers. How am I able to compare each of them and not get any duplicates?
I have extensively looked through Java documentation and asked my lectures and I can't get a working answer. I understand the concept, what I'm meant to do, but just can't get the coding right.
Here is my code:
public static void main(String[] args) {
int[] secret = new int[5];
//int[] secret = {0,0,0,0,0};
int[][] num = new int[3][5];
int correctL1 = 0;
int correctL2 = 0;
int correctL3 = 0;
for (int i = 0; i<5; i++){ // to get secret numbers.
secret[i] = (int) ((Math.random() * (40 - 1)) + 1);
}
System.out.println(Arrays.toString(secret));
}
I have tried putting this into the loop to get another number but it's still giving me duplicates.
if(((secret[i] == secret[0]) || (secret[i] == secret[1]) ||
(secret[i] == secret[2]) || (secret[i] == secret[3]) ||
(secret[i] == secret[4])) || (secret[i] != 0)) {
secret[i] = ((int) ((Math.random() * (40 - 1)) + 1));
}
In Java 8, you can use Random#ints to easily generate an array of distinct random numbers:
int[] secret = new Random().ints(1, 40).distinct().limit(5).toArray();
Ideone Demo
Otherwise, you can generate a Set<Integer> by using a while loop:
Set<Integer> secret = new HashSet<>();
Random gen = new Random();
while (secret.size() < 5) {
secret.add(gen.nextInt(40 - 1) + 1);
}
Simply use a Set<Integer> to keep the already generated numbers and iterate as long as the generated number is part of the generated numbers.
Set<Integer> existing = new HashSet<>();
for (int i = 0; i<5; i++){ // to get secret numbers.
// Loop until the generated number is not part of the already generated numbers
int value;
do {
value = (int) ((Math.random() * (40 - 1)) + 1);
} while (!existing.add(value));
secret[i] = value;
}
Why not creating a Set<Integer> (so you will not get any duplicate) and iterate until its size is 5 ?
Just use Set Collection..for better performance you can use below code
Set<Integer> data=new HashSet<Integer>();
If you want to get all elements by ascending order,you can use TreeSet
OR Other Logic is Every collection has contains method which returns boolean for e.g.data.contains(o)
while(true){
int[] secret = new int[5];
for (int i = 0; i < 5; i++) { // to get secret numbers.
secret[i] = (int) ((Math.random() * (40 - 1)) + 1);
}
System.out.println("Array:" + Arrays.toString(secret));
Set<Integer> mySet = new HashSet<Integer>();
for (int i = 0; i < 5; i++) { // to get secret numbers.
mySet.add(secret[i]);
}
if (mySet.size() == secret.length) {
System.out.println("OK");
break;
} else {
System.out.println("Not ok");
}
}

Resolving method calls from generic object in enhanced for loop

This is more than likely a simple question for someone who is more familiar with Java than I am. Here's the gist of my issue:
I have a function that basically generates the possible combinations of the objects contained within an ArrayList. Being that I have multiple objects that need to use this function, the function is screaming at me to be made generic. The issue I'm encountering, though, is that an enhanced for-loop is unable to resolve method calls from the generic iterator. I understand why this happening, but I'm not familiar enough with Java to know how to resolve this issue. In any case, here is my code:
private <T> ArrayList<T> determineIdealOrderCombination(ArrayList<T> orders, int position){
// Local Variable Declarations
List<ArrayList<T>> subsets = new ArrayList<>();
int k = orders.size()+1; // Add one due to the do-while loop
int theoreticalQuantity;
int indexOfMaxProfit;
double maxProfit;
int[] s; // Here we'll keep indices pointing to elements in input array
double[] profits; // Here we'll keep track of the profit of each combination
// Begin searching for valid combinations
do {
// Setup
k--;
s = new int[k];
profits = new double[k];
// Generate combinations
if ( (k <= orders.size()) && (k > 0) ) {
// Set the first index sequence: 0, 1, 2,...
for (int i = 0; (s[i] = i) < k - 1; i++) ;
subsets.add(getSubset(orders, s));
for (; ; ) {
int i;
// Find position of item that can be incremented
for (i = k - 1; i >= 0 && s[i] == orders.size() - k + i; i--) ;
if (i < 0) {
break;
} else {
s[i]++; // increment this item
for (++i; i < k; i++) { // fill up remaining items
s[i] = s[i - 1] + 1;
}
subsets.add(getSubset(orders, s));
}
}
// All combinations have been evaluated, now throw away invalid combinations that violate the upper limit
// and calculate the valid combinations profits.
for (int i = 0; i < subsets.size(); i++) {
// Calculate the final position
theoreticalQuantity = position;
profits[i] = 0;
for (T t : subsets.get(i)) {
theoreticalQuantity += t.getQuantity(); // <-- THE PROBLEM
profits[i] += calculateProjectedProfit(t.getSecurity(), t.getQuantity(), t.getPrice()); // <-- THE PROBLEM
}
if(theoreticalQuantity > _MAX_POSITION_PER_ASSET){
// Negate profits if final position violates the position limit on an asset
profits[i] = Double.MIN_VALUE;
}
}
}
else{
break;
}
}
while( (subsets.size() == 0) );
// Verify that the subset array is not zero - it should never be zero
if(subsets.size() == 0){
return new ArrayList<>();
}
// Return the most profitable combination, if any.
indexOfMaxProfit = -1;
maxProfit = Double.MIN_VALUE;
for(int i = 0; i < profits.length; i++){
if(profits[i] != Double.MIN_VALUE){
if(profits[i] > maxProfit){
maxProfit = profits[i];
indexOfMaxProfit = i;
}
}
}
if( (maxProfit > 0) && (indexOfMaxProfit != -1) ){
return subsets.get(indexOfMaxProfit);
}
else{
return new ArrayList<>();
}
}
Any help would be appreciated.
This is how you tell the compiler that the incoming objects have the relevant methods:
public interface MyCommonInterface {
public int getQuantity();
}
private <T extends MyCommonInterface> ArrayList<T> determineIdealOrderCombination(ArrayList<T> orders, int position) {
As an additional note, i would read some tutorials on generics before attempting to use them. they are a little tricky to get the hang of initially. however, once you put out a little effort to learn the basics, you should be in a much better place to actually utilize them.

Understanding an overflow issue in Java

Given a sorted integer array without duplicates, return the summary of
its ranges for consecutive numbers.
For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"].
I proposed the following solution:
public List<String> summaryRanges(int[] nums) {
if (nums == null){
return null;
}
if (nums.length == 0){
return new ArrayList<>();
}
if (nums.length == 1){
List<String> arr = new ArrayList<>();
arr.add(Integer.toString(nums[0]));
return arr;
}
List<String> summary = new ArrayList<>();
int n = nums.length;
int begin = nums[0];
int end;
for (int i = 1; i < n; i++) {
if (nums[i] - nums[i-1] > 1) {
end = nums[i-1];
if (begin == end){
summary.add(Integer.toString(begin));
}
else{
summary.add(Integer.toString(begin) + "->" + Integer.toString(end));
}
begin = nums[i];
}
}
if (nums[n-1] - nums[n-2] > 1){
summary.add(Integer.toString(nums[n-1]));
}
else{
summary.add(Integer.toString(begin) + "->" +Integer.toString(nums[n-1]));
}
return summary;
}
This program fails for the following example: [-2147483648, -2147483647, 2147483647] (returns the wrong answer: ["-2147483648->2147483647"])
I suspect this is due to an overflow issue, but I can't figure out why exactly. On the opposite, this example solution I found passes this test case:
public List<String> summaryRanges(int[] nums) {
List<String> result = new ArrayList<String>();
if(nums == null || nums.length==0)
return result;
if(nums.length==1){
result.add(nums[0]+"");
}
int pre = nums[0]; // previous element
int first = pre; // first element of each range
for(int i=1; i<nums.length; i++){
if(nums[i]==pre+1){
if(i==nums.length-1){
result.add(first+"->"+nums[i]);
}
}else{
if(first == pre){
result.add(first+"");
}else{
result.add(first + "->"+pre);
}
if(i==nums.length-1){
result.add(nums[i]+"");
}
first = nums[i];
}
pre = nums[i];
}
return result;
}
Why does this solution pass this test and not the one I proposed?
Yes, indeed, the problem is overflow.
The difference between your programs is, basically, that you are using the test:
nums[i] - nums[i-1] > 1
whereas the other program uses
nums[i]==pre+1
In a purely mathematical world, there should be no difference between comparing y to x+1 and comparing y-x to 1, but in the world of 32-bit integer, there is a big difference.
When you get to the numbers -Integer.MAX_VALUE and Integer.MAX_VALUE, which is what the numbers in your example array are, then your comparison is:
Integer.MAX_VALUE - -Integer.MAX_VALUE > 1
As the minus signs cancel each other, this means 2 * Integer.MAX_VALUE, which is larger than an int can hold, and you get an overflow. The result is -2 and that's not greater than 1.
In the other program's way, you would be asking whether
Integer.MAX_VALUE == - Integer.MAX_VALUE + 1
The left hand part is, of course, a legal integer. The right hand value is also a legal integer, because you are just stepping away from the minimum. Thus, no overflow, and the comparison would return false, which is good.
Can you try using absolute values wherever checking the differences:
Math.abs(nums[i]) - Math.abs(nums[i-1])
I suppose this looks like an issue here in case of negative numbers.

Checking to see if an integer has distinct numbers java

I'm having a difficult time with my program! For this method I have to check to see if all the numbers are distinct and I can't figure out for the life of me what I am doing wrong. I don't know if using an array is the best way to go. I must call the getDigit method.
for (int i = 0; i <= numDigits(number); i++) {
int digit = getDigit(number,i);
if (digit == getDigit(number,i)) {
return false;
}
}
return true;
You can first get each digit from the number and add them to a HashSet, then compare the size of HashSet with the number of digits present in the number
You can try this code:
public static void main(String[] args) {
int val = 123554;
Set<Integer> set = new HashSet<Integer>(); // HashSet contains only unique elements
int count = 0; // keeps track of number of digits encountered in the number
// code to get each digit from the number
while (val > 0) {
int tempVal = val % 10;
set.add(tempVal); // add each digit to the hash set
// you can have a boolean check like if(!set.add(tempVal)) return false; because add() returns false if the element is already present in the set.
val = val / 10;
count++;
}
if (count == set.size()) {
System.out.println("duplicate digit not present");
} else {
System.out.println("duplicate digit present");
}
}
Splitting Int into single digits:
Use something similar to this:
Code to print the numbers in the correct order:
int number; // = and int
LinkedList<Integer> stack = new LinkedList<Integer>();
while (number > 0) {
stack.push( number % 10 );
number = number / 10;
}
while (!stack.isEmpty()) {
print(stack.pop());
}
Source
Checking for Duplicates:
Again, something similar to this:
public static boolean duplicates (int [] x, int numElementsInX ) {
Set<Integer> set = new HashSet<Integer>();
for ( int i = 0; i < numElementsInX; ++i ) {
if ( set.contains( x[i])) {
return true;
}
else {
set.add(x[i]);
}
}
return false;
}
Source
Alternative
If you can split the array, an alternative could be to use:
int[] numbers = { 1, 5, 23, 2, 1, 6, 3, 1, 8, 12, 3 };
Arrays.sort(numbers);
for(int i = 1; i < numbers.length; i++) {
if(numbers[i] == numbers[i - 1]) {
System.out.println("Duplicate: " + numbers[i]);
}
}
i suppose that you want to compare for example the number 12345 with 23145, and prompt out a false, and if they are the same (digit by digit, prompt a true) , am i right?.
If you want to do this, you should make 2 arrays and you have to make sure to compare each position of both so you can compare digit by digit.
Hope it helps you
public boolean unique(int theNumber) {
String number = new Integer(theNumber).toString();
Set<Character> set = new LinkedHashSet<Character>();
for(char c:number.toCharArray()) {
set.add(Character.valueOf(c));
}
return number.length() == set.size();
}

Categories