Count different values in array in Java - java

I'm writing a code where I have an int[a] and the method should return the number of unique values. Example: {1} = 0 different values, {3,3,3} = 0 different values, {1,2} = 2 different values, {1,2,3,4} = 4 different values etc. I am not allowed to sort the array.
The thing is that my method doesn't work probably. There is something wrong with my for statement and I can't figure it out.
public class Program
{
public static void main(String[] args)
{
int[] a = {1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
//run: 4 //should be 3
}
public static int differentValuesUnsorted(int[] a)
{
int values; //values of different numbers
if (a.length < 2)
{
return values = 0;
}else if (a[0] == a[1])
{
return values = 0;
}else
{
values = 2;
}
int numberValue = a[0];
for (int i = a[1]; i < a.length; i++)
{
if (a[i] != numberValue)
{
numberValue++;
values++;
}
}
return values;
}
}
Can anybody help?

This is actually much simpler than most people have made it out to be, this method works perfectly fine:
public static int diffValues(int[] numArray){
int numOfDifferentVals = 0;
ArrayList<Integer> diffNum = new ArrayList<>();
for(int i=0; i<numArray.length; i++){
if(!diffNum.contains(numArray[i])){
diffNum.add(numArray[i]);
}
}
if(diffNum.size()==1){
numOfDifferentVals = 0;
}
else{
numOfDifferentVals = diffNum.size();
}
return numOfDifferentVals;
}
Let me walk you through it:
1) Provide an int array as a parameter.
2) Create an ArrayList which will hold integers:
If that arrayList DOES NOT contain the integer with in the array
provided as a parameter, then add that element in the array parameter
to the array list
If that arrayList DOES contain that element from the int array parameter, then do nothing. (DO NOT ADD THAT VALUE TO THE ARRAY LIST)
N.B: This means that the ArrayList contains all the numbers in the int[], and removes the repeated numbers.
3) The size of the ArrayList (which is analogous to the length property of an array) will be the number of different values in the array provided.
Trial
Input:
int[] numbers = {3,1,2,2,2,5,2,1,9,7};
Output: 6

First create distinct value array, It can simply create using HashSet.
Then alreadyPresent.size() will provide number of different values. But for the case such as -{3,3,3} = 0 (array contains same elements); output of alreadyPresent.size() is 1. For that use this simple filter
if(alreadyPresent.size() == 1)){
return 0;
}
Following code will give the count of different values.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Demo {
public static void main(String[] args)
{
int array[] = {9,9,5,2,3};
System.out.println(differentValuesUnsorted(array));
}
public static int differentValuesUnsorted(int[] array)
{
Set<Integer> alreadyPresent = new HashSet<Integer>();
for (int nextElem : array) {
alreadyPresent.add(nextElem);
}
if(alreadyPresent.size() == 1){
return 0;
}
return alreadyPresent.size();
}
}

You can use a HashSet, which can only contain unique elements. The HashSet will remove the duplicated items and you can then get the size of the set.
public static int differentValuesUnsorted(int[] a) {
Set<Integer> unique = new HashSet<Integer>();
for (int val : a) {
unique.add(val); // will only be added if a is not in unique
}
if (unique.size() < 2) { // if there are no different values
return 0;
}
return unique.size();
}

For small arrays, this is a fast concise method that does not require the allocation of any additional temporary objects:
public static int uniqueValues(int[] ids) {
int uniques = 0;
top:
for (int i = 0; i < ids.length; i++) {
final int id = ids[i];
for (int j = i + 1; j < ids.length; j++) {
if (id == ids[j]) continue top;
}
uniques++;
}
return uniques;
}

Try this:
import java.util.ArrayList;
public class DifferentValues {
public static void main(String[] args)
{
int[] a ={1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
}
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> ArrUnique = new ArrayList<Integer>();
int values=0; //values of different numbers
for (int num : a) {
if (!ArrUnique.contains(num)) ArrUnique.add(num);
}
values = ArrUnique.size();
if (values == 1) values = 0;
return values;
}
}
input:{1,1,1,1,1} - output: 0
input:{1,2,3,1} - output: 3

Try this... its pretty simple using ArrayList. You don't even need two loop. Go on
import java.util.*;
public class distinctNumbers{
public static void main(String []args){
int [] numbers = {2, 7, 3, 2, 3, 7, 7};
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<numbers.length;i++)
{
if(!list.contains(numbers[i])) //checking if the number is present in the list
{
list.add(numbers[i]); //if not present then add the number to the list i.e adding the distinct number
}
}
System.out.println(list.size());
}
}

Try this simple code snippet.
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> list=new ArrayList<Integer>(); //import java.util.*;
for(int i:numbers) //Iterate through all the elements
if(!list.contains(i)) //checking for duplicate element
list.add(i); //Add to list if unique
return list.size();
}

What about this?
private <T> int arrayDistinctCount(T[] array) {
return Arrays.stream(array).collect(Collectors.toSet()).size();
}

Use a set to remove duplicates
public static int differentValuesUnsorted(int[] a) {
if (a.length < 2) {
return 0;
}
Set<Integer> uniques = new HashSet<>(a);
return singleUnique.size();
}

Related

Find sum of subsequent 3 elements of an array

I need to sum the three consecutive elements of an array when appending numbers to the same array dynamically and return true if the sum is equal to the argument value. I have already written the code below and it all return required output but it fails for some test cases( I don't have the the exact test cases), Can anybody tell me what exact scenario which my programme can be failed?
import java.util.LinkedList;
import java.util.List;
public class Test {
List<Integer> mergeList = new LinkedList<Integer>();
List<List<Integer>> allList = new LinkedList<List<Integer>>();
List<Integer> tail;
int from = 0;
int to = 0;
public void addLast(int[] list) {
allList.removeAll(allList);
for(int i : list) {
mergeList.add(i);
}
if (mergeList.size() > 0) {
int j = 0;
while(to < mergeList.size()){
from = j;
to = j + 3;
tail = mergeList.subList(from, to);
j++;
allList.add(tail);
}
}
}
public boolean containsSum3(int sum) {
boolean retVal = false;
for (List<Integer> sum3List : allList) {
if (sum3List.stream().mapToInt(Integer::intValue).sum() == sum) {
retVal = true;
}
}
return retVal;
}
public static void main(String[] args) {
Test s = new Test();
s.addLast(new int[] { 1, 2, 3 });
System.out.println(s.containsSum3(6));
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 4 });
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 5, 2});
System.out.println(s.containsSum3(11));
s.addLast(new int[] { 0, -1 });
System.out.println(s.containsSum3(7));
System.out.println(s.containsSum3(2));
}
}
Output:
true
false
true
true
true
false
I generated large random collections of integers and couldn't find any obvious cases your code fails for beyond the insufficient elements. Incidentally, the function I wrote to check if a list has any consecutive n elements that sum to a given value was:
public static boolean containsSum(List<Integer> list, int sum, int n) {
return IntStream.range(0, list.size() - n + 1)
.anyMatch(i -> list.subList(i, i + n).stream()
.reduce(0, Integer::sum) == sum);
}
I can't see any reason for your code that keeps all the list of lists: the space / time tradeoff doesn't make a lot of sense. I suggest you could simplify addLast to just add the elements to mergeList. There are a bunch of stylistic issues with your code but I'm sure you'll work those out in your own time.

Bug in methods that find unmatched integers between two arrays

I am trying to do the following function in the java code below: I am trying to generate the array of integers that do not match between 'match' array and 'original' array.
To do this I created a subarray class, a class that allows me to get the rest of unmatched elements in the two arrays (match and original), and lastly, I have a class that is called match_sequence that does the job.
My problem is there is a bug in the function that I have no idea why, for example if my input is int[] original = {1,0}; int[] match = {1,0}; I get the residual for both original and match with [0] when it should be [], and if my inputs are {1,0,0},{1,0,0}, there is no such problem but if my inputs are both {1,0,1,0,0}, I got [0, 0] in both elements as unmatched array, when again, the result should be [] because those are perfectly matched arrays.
This is driving me insane can someone please let me know where is the bug?
import java.util.Arrays;
public class subarray
{
// Generic method to get subarray of a non-primitive array
// between specified indices
public static<T> int[] subArray(int[] arr, int beg, int end) {
return Arrays.copyOfRange(arr, beg, end+1);
}
}
import java.util.Arrays;
public class results {
private int[] array1; //array2
private int[] array2; //array1
public results (int[] result1, int[] result2)
{
array1 = result1;
array2 = result2;
//return results(array1,array2);
}
public int[] getArray1() { return array1; }
public int[] getArray2() { return array2; }
}
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class match_sequence {
public static results match_sequence(int[] original_rest,int[] match) {
if(match.length <= original_rest.length) {
for (int j = 0; j < match.length; j++) {
//set a initial starting point plus i if we are not starting from 0
if (original_rest[j]==match[j]) {
match = subarray.subArray(match,j+1,match.length-1);
original_rest = subarray.subArray(original_rest,j+1,original_rest.length-1);
} else if (original_rest[j]!=match[j]) {
original_rest = subarray.subArray(original_rest,j,original_rest.length-1);
match = subarray.subArray(match,j,match.length-1);
if(original_rest[0]!=match[0]){
System.out.println("This is not an interweave of two sub elements!");
}
break;
}
}
}
if(match.length > original_rest.length) {
for (int j = 0; j < original_rest.length; j++) {
//set a initial starting point plus i if we are not starting from 0
if (original_rest[j]==match[j]) {
match = subarray.subArray(match,j+1,match.length-1);
original_rest = subarray.subArray(original_rest,j+1,original_rest.length-1);
} else if (original_rest[j]!=match[j]) {
original_rest = subarray.subArray(original_rest,j,original_rest.length-1);
match = subarray.subArray(match,j,match.length-1);
if(original_rest[0]!=match[0]) {
System.out.println("This is not an interweave of two sub elements!");
}
break;
}
}
}
return new results(match,original_rest);
}
//here is the problem:
public static void main(String[] args)
{
int[] original = {1,0};
int[] match = {1,0};
//bug1: there is mismatch over here and should be resolved through debugging
int[] rest_of_match = match_sequence(original,match).getArray1();
System.out.println("Final match"+Arrays.toString(rest_of_match));
int[] original_rest = match_sequence(original,match).getArray2();
System.out.println("Final original"+Arrays.toString(original_rest));
}
}
The problem is inside match_sequence() method. You slice first element of an array, but you don't move j index back. To do so add such line at the end of for loop:
j--;
Also match_sequence() contains big code duplication. If statements are redudant, you can combine them in one for loop:
public static results match_sequence(int[] original_rest, int[] match) {
for(int j = 0; j < Math.min(match.length, original_rest.length); j++) {
//set a initial starting point plus i if we are not starting from 0
if(original_rest[j] == match[j]) {
match = subarray.subArray(match, j + 1, match.length - 1);
original_rest = subarray.subArray(original_rest, j + 1, original_rest.length - 1);
} else if(original_rest[j] != match[j]) {
original_rest = subarray.subArray(original_rest, j, original_rest.length - 1);
match = subarray.subArray(match, j, match.length - 1);
if(original_rest[0] != match[0]) {
System.out.println("This is not an interweave of two sub elements!");
}
break;
}
j--;
}
return new results(match, original_rest);
}
Output:
Final match[]
Final original[]
Update:
Picture below shows why you need to move j back. If you don't do that, then you will skip second element of list.

Method inefficiency

This is from code fights. The method works but is apparently taking too long for large inputs. Can someone please explain what is inefficient about this solution?
Question:
Given an array of integers, write a function that determines whether the array contains any duplicates. Your function should return true if any element appears at least twice in the array, and it should return false if every element is distinct.
Example
For a = [1, 2, 3, 1], the output should be
containsDuplicates(a) = true.
There are two 1s in the given array.
Solution:
static boolean containsDuplicates(int[] a) {
boolean elementRepeat = false;
for (int loop1 = 0; loop1 < a.length; loop1++){
for (int loop2 = 0; loop2 < a.length; loop2++){
if (a[loop1] == a[loop2] && loop1!=loop2){
elementRepeat = true;
return elementRepeat;
}
}
}
return elementRepeat;
}
One way to do this is by storing the array in Set and then comparing the length of the array and set. Here is how:
static boolean containsDuplicates(int[] array) {
HashSet<Integer> integers = new HashSet<>();
Arrays.stream(array).forEach(integers::add);
array.length == integers.size();
}
I think that #Henry did a very good sugestion.
This is an example:
import java.util.HashSet;
import java.util.Set;
public class Test4 {
public static void main(String[] args) {
Integer[] arrayInt = {1, 2, 3, 1};
Set<Integer> integers = new HashSet<Integer>();
boolean hasDuplicates = false;
for (Integer integerNumber : arrayInt) {
if (!integers.add(integerNumber)) {
hasDuplicates = true;
break;
}
}
System.out.println("Contains duplicates? " + hasDuplicates);
}
}
And it will print:
Contains duplicates? true

Shuffling elements in an Array (Java)

I need a shuffle method to shuffle elements of an array which holds objects from another class. At the moment I wrote this code to test with integers first, but it seems to not working perfectly. Most of the elements are being duplicated.
Can someone please spot the mistake?
And also come up with a more efficient method for this.
I am not sure if I can use collections.shuffle because I have further use of my shuffled array later.
public static void shuffle()
{
int[] a = new int[52];
int count = 0;
int random = 0;
while (count!=51){
random = (int)(Math.random() * 52);
for (int i=0; i <=count; i++){
if (a[count] != b[random])
result = true;
}
if (result){
a[count] = b[random];
count++;
}
b = Arrays.copyOf(a, a.length);
}
}
First you should not define shuffle() in this way. I would treat b as a parameter and pass it into shuffle() instead of a static field (as your shuffle() is declared as static, your b is also static right? It looks strange to share b between all instances), and result is declared as a local variable.
This part
for (int i=0; i <=count; i++){
if (a[count] != b[random])
result = true;
}
checks whether any one of a[0], a[1] until a[count] is not equal to b[random]. If yes, then assign b[random] to a[count] and increase count by 1. As a[] is not initialized, it is only an array of 0. (a[count] != b[random]) appears to be always true and hence result is true.
Then, for this part,
if (result){
a[count] = b[random];
count++;
}
say for example random=5, then at the first round of the while loop a[0]=b[5], count=1 (due to count++), and b becomes an array of b[5] and a series of 0. (Due to
b = Arrays.copyOf(a, a.length);
all other elements are replaced by 0.)
Edit: Here I provide a simple method, not thoroughly tested, but should work:
public static int[] shuffle(int[] array) {
int[] a = new int[array.length];
//convert int[] to ArrayList<Integer>
ArrayList<Integer> list = new ArrayList<>();
for (int i: array)
list.add(i);
//now shuffle:
for (int i=0; i<array.length; i++) {
int rand = (int)(Math.random()*list.size());
a[i] = list.remove(rand);
}
return a;
}
The array returned is shuffled. Actually I can't say the method "shuffles" the array. It simply creates an empty array, and repeatedly selects an element randomly and put it at the front.
Edit2: This really "shuffles", and this is another approach: does not return a new array. It shuffles the array, 100 times.
public static void shuffle(int[] array) {
for (int i=0; i<100; i++) {
int r1 = (int)(Math.random()*array.length);
int r2 = (int)(Math.random()*array.length);
int tmp = array[r1];
array[r1] = array[r2];
array[r2] = tmp;
}
}
import java.util.Random;
public class Shuffle {
public static void main(String[] args) {
Integer[] a = new Integer[52];
for (Integer i=0;i<a.length;i++) a[i] = i+1;
// Let's shuffle
Random rd = new Random();
for (Integer i=0;i<a.length;i++){
Integer changeBy = rd.nextInt(a.length);
Integer aux=a[i];
a[i]=a[changeBy];
a[changeBy] = aux;
}
// Now show the shuffled array
for (Integer i=0;i < a.length; i++) System.out.print(a[i]+",");
}
}
Hope this small algorithm helps you. As you can see from 2 different runs, it really shuffles your array:
11,1,24,13,28,15,25,48,5,22,12,32,29,42,34,7,33,31,47,18,51,40,8,17,41,20,6,36,21,45,27,52,38,10,30,14,23,19,43,4,50,46,44,3,49,37,35,2,9,26,16,39
3,10,37,26,41,15,28,52,6,24,20,43,33,21,51,32,25,40,50,8,7,5,4,35,13,16,49,17,29,47,12,14,36,39,45,30,2,42,23,38,31,19,27,46,34,11,18,1,22,48,9,44
Why no you HashSet for shuffle?
Elements in java.lang.HashSet are shuffling by their hashcode.
public static void shuffle()
{
int [] b; // you origin array
Set<Integer> temp = new HashSet<Integer>();
for (int i : b) {
temp.add(i);
}
Integer [] a = new Integer[b.length];
a = temp.toArray(a); // new shuffle array
}

Sorting two arrays simultaneously

I'm learning and understanding Java now, and while practising with arrays I had a doubt. I wrote the following code as an example:
class example
{
public static void main(String args[])
{
String a[] = new String[] {"Sam", "Claudia", "Josh", "Toby", "Donna"};
int b[] = new int[] {1, 2, 3, 4, 5};
for(int n=0;n<5;n++)
{
System.out.print (a[n] + "...");
System.out.println (b[n]);
}
System.out.println (" ");
java.util.Arrays.sort(a);
for(int n=0;n<5;n++)
{
System.out.print (a[n] + "...");
System.out.println (b[n]);
}
}
In a nutshell, this class created two arrays with five spaces each. It fills one with names of characters from the West Wing, and fills the other with numbering from one to five. We can say that the data in these two strings corresponds to each other.
Now, the program sorts the array with the names in it using Arrays.sort(). After printing the array again, you can see that while the names are now in alphabetical order, the numbers do not correspond anymore as the second array is unchanged.
How can I shuffle the contents of the second array to match the sort requirements of the first? The solution must also be flexible to allow for changes in the scope and size of the program. Please do not post any answers asking me to change my methodology with the arrays, or propose a more 'efficient' way of doing things. This is for educational purposed and I'd like a straight solution to the example code provided. Thanks in advance!
EDIT: I do NOT want to create an additional class, however I think some form of sorting through nested loops might be an option instead of Arrays.sort().
Below is the code without using any Map Collection, but if you want to use Map then it becomes very easy. Add both the arrays into map and sort it.
public static void main(String args[]) {
String a[] = new String[] {
"Sam", "Claudia", "Josh", "Toby", "Donna"
};
int b[] = new int[] {
1, 2, 3, 4, 5
};
for (int n = 0; n < 5; n++) {
System.out.print(a[n] + "...");
System.out.println(b[n]);
}
System.out.println(" ");
//java.util.Arrays.sort(a);
/* Bubble Sort */
for (int n = 0; n < 5; n++) {
for (int m = 0; m < 4 - n; m++) {
if ((a[m].compareTo(a[m + 1])) > 0) {
String swapString = a[m];
a[m] = a[m + 1];
a[m + 1] = swapString;
int swapInt = b[m];
b[m] = b[m + 1];
b[m + 1] = swapInt;
}
}
}
for (int n = 0; n < 5; n++) {
System.out.print(a[n] + "...");
System.out.println(b[n]);
}
}
Some people propose making a product type. That is feasible only if the amount of elements is small. By introducing another object you add object overhead (30+ bytes) for each element and a performance penalty of a pointer (also worsening cache locality).
Solution without object overhead
Make a third array. Fill it with indices from 0 to size-1. Sort this array with comparator function polling into the array according to which you want to sort.
Finally, reorder the elements in both arrays according to indices.
Alternative solution
Write the sorting algorithm yourself. This is not ideal, because you might make a mistake and the sorting efficiency might be subpar.
You have to ZIP your two arrays into an array which elements are instances of a class like:
class NameNumber
{
public NameNumber(String name, int n) {
this.name = name;
this.number = n;
}
public String name;
public int number;
}
And sort that array with a custom comparator.
Your code should be something like:
NameNumber [] zip = new NameNumber[Math.min(a.length,b.length)];
for(int i = 0; i < zip.length; i++)
{
zip[i] = new NameNumber(a[i],b[i]);
}
Arrays.sort(zip, new Comparator<NameNumber>() {
#Override
public int compare(NameNumber o1, NameNumber o2) {
return Integer.compare(o1.number, o2.number);
}
});
You should not have two parallel arrays. Instead, you should have a single array of WestWingCharacter objects, where each object would have a field name and a field number.
Sorting this array by number of by name would then be a piece of cake:
Collections.sort(characters, new Comparator<WestWingCharacter>() {
#Override
public int compare(WestWingCharacter c1, WestWingCharacter c2) {
return c1.getName().compareTo(c2.getName();
}
});
or, with Java 8:
Collections.sort(characters, Comparator.comparing(WestWingCharacter::getName));
Java is an OO language, and you should thus use objects.
What you want is not possible because you don't know internally how Arrays.sort swap the elements in your String array, so there is no way to swap accordingly the elements in the int array.
You should create a class that contains the String name and the int position as parameter and then sort this class only with the name, providing a custom comparator to Arrays.sort.
If you want to keep your current code (with 2 arrays, but this not the ideal solution), don't use Arrays.sort and implement your own sorting algorithm. When you swap two names, get the index of them and swap the two integers in the other array accordingly.
Here is the answer for your query.
public class Main {
public static void main(String args[]){
String name[] = new String[] {"Sam", "Claudia", "Josh", "Toby", "Donna"};
int id[] = new int[] {1, 2, 3, 4, 5};
for ( int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int dtmp=0;
String stmp=null;
if (id[i] > id[j]) {
dtmp = rate[i];
id[i] = id[j];
id[j] = dtmp;
stmp = name[i];
name[i]=name[j];
name[j]=stmp;
}
}
}
System.out.println("Details are :");
for(int i=0;i<n;i++){
System.out.println(name[i]+" - "+id[i]);
}
}
}
The same solution, as a function that can be added to some utils class:
public static final boolean INCREASING = true;
public static final boolean DECREASING = false;
#SuppressWarnings("unchecked")
public static <T extends Comparable, U extends Object> void bubbleSort(ArrayList<T> list1, ArrayList<U>list2, boolean order) {
int cmpResult = (order ? 1 : -1);
for (int i = 0; i < list1.size() - 1; i++) {
for (int j = 0; j <= i; j++) {
if (list1.get(j).compareTo(list1.get(j+1)) == cmpResult) {
T tempComparable = list1.get(j);
list1.set(j , list1.get(j + 1));
list1.set(j + 1 , tempComparable);
U tempObject = list2.get(j);
list2.set(j , list2.get(j + 1));
list2.set(j + 1 , tempObject);
}
}
}
}
The arrays are not linked in any way. Like someone pointed out take a look at
SortedMap http://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html
TreeMap http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
import java.util.*;
class mergeArrays2
{
public static void main(String args[])
{
String a1[]={"Sam", "Claudia", "Josh", "Toby", "Donna"};
Integer a2[]={11, 2, 31, 24, 5};
ArrayList ar1=new ArrayList(Arrays.asList(a1));
Collections.sort(ar1);
ArrayList ar2=new ArrayList(Arrays.asList(a2));
Collections.sort(ar2);
System.out.println("array list"+ar1+ " "+ar2);
}
}

Categories