Java - How to find if 2 arrays are duplicates of each other? - java

Given 2 arrays, how can one find out quickly if they are identical by value to each other?
For example, arr1 and arr2 are considered to be identical because they contain equal values, while arr2 and arr3 aren't
int[] arr1 = new int[]{-1, 0, 1};
int[] arr2 = new int[] {-1, 0, 1};
int[] arr3 = new int[] {0, -1, 1}; // not identical
What is the quickest way to find out? I know a for loop will work, but can you do faster, say, constant time? HashSet doesn't work, because technically arr1 and arr2 are different objects
Edit1: what if there are N arrays, and we want to filter out the unique ones?

Arrays.equals will check for content-based equality of two arrays; it is O(n), which is optimal. You can't do better than O(n).
If you want to filter out the unique arrays among n arrays, you might write something like this:
import java.nio.IntBuffer;
int[][] distinctArrays(int[]... arrays) {
Set<IntBuffer> set = new HashSet<>();
for (int[] array : arrays) {
set.add(IntBuffer.wrap(array));
}
int[][] result = new int[set.size()][];
int i = 0;
for (IntBuffer wrappedArray : set) {
result[i++] = wrappedArray.array();
}
return result;
}
...or, with Java 8...
int[][] distinctArrays(int[]... arrays) {
return Stream.of(arrays)
.map(IntBuffer::wrap)
.distinct()
.map(IntBuffer::array)
.toArray(int[][]::new);
}

There's an equals method in the Arrays class, here's the JavaDoc: Arrays.equals

Related

How to check if a list is a key in hashmap?

I have a map from List to String (keys are lists).
the keys are converted from int arrays to lists.
adding a pair example:
int[] arr = { 1, 2, 3, 4, 5 };
my_map.put(Arrays.asList(arr), "12345");
Now when i check if my_map contains some other list, i will always get null, example:
int[] test_arr = { 1, 2, 3, 4, 5 };
if (my_map.get(Arrays.asList(test_arr)) != null) { // always null!
// do something
}
I know what the problem is: it's comparing the addresses of the lists, and NOT the values!
How can i compare those lists values ?
The problem you mentioned is correct, I’ll suggest replacing the key value to be string to list. But if you insist for your reasons you can envelope the list implementation with your own class and override the equal to function to be based on the values and not the address.
Some map implementations allow you to instantiate your map with a Comparator (TreeMap for example).
This way you can provide your own implementation to determine if the Keys are equal.
Your comparator function returns an int with a value that is greater than zero, less than zero, or zero if the two values are equal.
My advice is to change a little bit the storage in order to have the same functionality. Means to check if a predefined list is within the stucture.
You do not need a Map since it's not required to add values, just use the values within List. Further more use Objects and not primitives.
Briefly a List of Lists will fit well in this case. Notice, the order of elements in List matters. If do not care order you could just sort both lists before compare.
public class TestListArr {
public static void main(String[] args) {
List<List<Integer>> list = new ArrayList<>();
Integer[] arr = { 1, 2, 3, 4, 5 };
//just check it
//int[] arr1 = {1,2,3};
//Arrays.asList(arr1).forEach(System.out::println);
//Arrays.asList(arr).forEach(System.out::println);
list.add(Arrays.asList(arr));
Integer[] test_true = { 1, 2, 3, 4, 5 };
System.out.println(check(list,test_true));
Integer[] test_false = { 1, 2, 3, 4 };
System.out.println(check(list,test_false));
//direct test
//System.out.println(Arrays.asList(arr).equals(Arrays.asList(test_true)));
}
public static boolean check(List<List<Integer>> list, Integer[] test)
{
for(List<Integer> lst:list)
{
if(lst.equals(Arrays.asList(test)))
return true;
}
return false;
}
}
Output
true
false
The List objects that you are creating only contain one element, an object of type int[]. int[] uses identity to test equality, not array content. Instead, convert the array content to a list with equivalent content:
static List<Integer> toList(int[] arr) {
return IntStream.of(arr).boxed().collect(Collectors.toList());
}

How to fix list.contains(object) not returning the good boolean variable

I am trying to make a list with some array, generated random, within a range and with a fixed size. The problem is, when I want to see if an array is already in the list (list.contains(array)) it's not returning the good boolean variable. This is how this code looks like, and I have no idea from where's the problem:
List<int[]> list = new ArrayList<int[]>();
int[] v = new int[n];
int n = 2, val_max = 3;
while (list.size() != max) {
v = getRandomArray(n, 1, val_max);
if (list.contains(v) == false)
list.add(v);
}
I expect the output for that to be { {1, 2} {2, 1} {1, 3} {3, 1} {2, 3} {3, 2} } but the output keeps changing... It always doubles one or two of the above values which is what made me think that the problem must be from the contains function.
List.contains uses Object.equals to check for equality, but arrays use reference equality, not content equality. So .contains will always return false.
Unfortunately, for arrays specifically, there really are only two options:
Rewrite the logic of contains yourself, using Arrays.equals.
Wrap the arrays in a new object of your own creation and write its equality methods appropriately.

How can I sort Arrays in a Collection?

I have a a List of Objects. Those Objects have (amongst others) a private int Array (if it helps, I can transfer it into a List). There is a public Getter for this Array. All Arrays are the same size.
I want to sort the Object based on their Arrays like this:
Unsorted:
{[0, 1, 4, 5],
[0, 0, 2, 3],
[0, 1, 1, 2]}
Sorted:
{[0, 0, 2, 3],
[0, 1, 1, 2],
[0, 1, 4, 5]}
In Words (it's called lexicographical):
compare the first int of each array
if they are equal, compare the next int of each array (and so on)
if they aren't equal the result of the comparison is the end result.
I manage to search them for e.g. only the first element of the array with a normal Comparator but I don't know how to search them for all.
A nice Java 8 solution is
static final Comparator<CustomObject> COMPARATOR = (o1, o2) -> {
int[] arr1 = o1.getArray();
int[] arr2 = o2.getArray();
return IntStream.range(0, arr1.length)
.map(i -> Integer.compare(arr1[i], arr2[i]))
.filter(i -> i != 0)
.findFirst()
.orElse(0);
};
Then, given a List<CustomObject>, you can do
list.sort(COMPARATOR);
(The Comparator only works for arrays of the same length. You may want to modify it).
I have a Collection (preferable some kind of List) of Objects
[...]
Now I want to sort the Object based on their Arrays
For it to be meaningful at all, the Collection in question must be one that preserves order and allows you to reorder elements. In terms of the high-level Collections interfaces, only List has the required properties, so let's presume that your Collection is, indeed, a List.
The standard way to sort a List is to use one of the two Collections.sort() methods. One requires the list elements to implement Comparable, and the other, more general, one requires you to provide an object implementing Comparator for use in determining the desired relative order of the objects.
Arrays do not implement Comparable (which is equivalent to saying that they have no "natural order"), but the class of the objects containing them could be made to do so. It is probably better form, however, to write a separate Comparator class that implements the order you want, and use an instance of that class.
If I am understanding it correctly, following straightforward approach should work:
public class SortArrays {
public static void main(String[] args) {
List<int[]> listOfArrays = new ArrayList<>(4);
listOfArrays.add(new int[]{0, 1, 4, 5});
listOfArrays.add(new int[]{0, 0, 2, 3});
listOfArrays.add(new int[]{0, 1, 1, 2});
Collections.sort(listOfArrays, (o1, o2) -> {
for (int i = 0; i < o1.length; i++) {
if (o1[i] < o2[i])
return -1;
if (o1[i] > o2[i])
return 1;
}
return 0;
});
listOfArrays.forEach(a -> System.out.println(Arrays.toString(a)));
}
}
It produces:
[0, 0, 2, 3]
[0, 1, 1, 2]
[0, 1, 4, 5]
and that's what you seem to expect.
Suppose your class looks something like this, and you can't modify it.
final class MyClass
{
private final int[] key;
MyClass(int[] key)
{
this.key = key.clone();
}
public int[] getKey()
{
return key.clone();
}
}
Then, you can define an ordering for instances of MyClass by implementing the Comparator interface. To be more general, I'm actually going to implement a comparator for int[]:
final class IntArrayComparator
implements Comparator<int[]>
{
#Override
public int compare(int[] a, int[] b)
{
int n = Math.min(a.length, b.length);
for (int idx = 0; idx < n; ++idx) {
if (a[idx] != b[idx])
return (a[idx] < b[idx]) ? -1 : +1;
}
return a.length - b.length;
}
}
Given this new comparator, and your existing type, it's easy to sort:
final class Test
{
public static void main(String... arg)
{
/* Create your list somehow... */
List<MyClass> list = new ArrayList<>();
list.add(new MyClass(new int[]{0, 1, 4, 5}));
list.add(new MyClass(new int[]{0, 0, 2, 3}));
list.add(new MyClass(new int[]{0, 1, 1, 2}));
/* Now sort the list. */
list.sort(Comparator.comparing(MyClass::getKey, new IntArrayComparator()));
/* Display the result... */
list.stream().map(MyClass::getKey).map(Arrays::toString).forEach(System.out::println);
}
}
You should get the output:
[0, 0, 2, 3]
[0, 1, 1, 2]
[0, 1, 4, 5]
The comparing() factory method I am using takes two arguments: a Function to "extract" a key from each object in the list, and a Comparator that can compare the extracted keys. If the extracted key has a natural ordering, and implements Comparable (for example, it's a String), then it isn't necessary to specify a Comparator.
Alternatively, if you can modify MyClass, you could give it a natural order by implementing Comparable and moving the int[] comparison to its compareTo() method, as shown in other answers. Then you can use the sort() method without arguments.
In order to sort a list of arrays of int, you want a function that performs a lexicographic comparison of an array of ints. This is usually expressed as a Comparator<int[]> in Java. The usual way to implement such a function is to compare corresponding values left-to-right until a mismatch is found; that mismatch determines the order. If the end of an array is reached without finding a mismatch, the shorter array is usually considered less than the longer one. If the lengths are equal, and all values are equal, the arrays are considered equal.
Other answers have used anonymous inner classes or lambdas for this function, but for things like this I prefer an ordinary method that has the right "shape", that is, that takes two int[] arguments and returns an int which is the result of the comparison. This enables it to be used as the target of a method reference.
int arrayCompare(int[] a, int[] b) {
int len = Math.min(a.length, b.length);
for (int i = 0; i < len; i++) {
int c = Integer.compare(a[i], b[i]);
if (c != 0) {
return c;
}
}
return a.length - b.length;
}
Note the careful use of Integer.compare() instead of subtraction, avoiding potential problems with overflow. Usage would be as follows:
List<int[]> arrays = Arrays.asList(
new int[] { 0, 1, 4, 5 },
new int[] { 0, 0, 2, 3 },
new int[] { 0, 1, 1, 2 }
);
arrays.sort(this::arrayCompare);
arrays.forEach(a -> System.out.println(Arrays.toString(a)));
In JDK 9, lexicographic array comparison functions have been added to the Arrays class. See Arrays.compare(int[], int[]). There are also overloads for the other primitive types and for reference types. The int[] overload replaces the arrayCompare function I wrote above, so you can rewrite the sort call as follows:
arrays.sort(Arrays::compare);
The advantage of the comparison functions in the Arrays class is that they can be handled specially by the JVM, which can, for example, use vector instructions to speed up array comparisons.
For your specific problem, it looks like you don't have a list of int[], but you have a list of objects of type MyObject that have an int[] that you want to use as the sort key. Suppose the way to get the array is by calling the method getArray(). You can sort the list as follows:
myObjects.sort(Comparator.comparing(MyObject::getArray, Arrays::compare));
Consider this object:
public class Foo {
private int[] values;
public Foo(int[] values) {
this.values = values;
}
}
To make a list of objects:
ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo(new int[] {0, 1, 4, 5}));
foos.add(new Foo(new int[] {0, 0, 2, 3}));
foos.add(new Foo(new int[] {0, 1, 1, 2}));
Now we want to sort our list of objects, so the first thing we should do is make our object implement Comparable. You should read more what the Comparable interface is, and how to implement it.
public class Foo implements Comparable<Foo> {
...
}
At this point your compiler will complain that you haven't implemented all of the methods required by the interface. So do that.
public class Foo implements Comparable<Foo> {
...
public int compareTo(Foo f) {
// Return a negative integer if this < f
// Return zero if this == f
// Return a positive integer if this > f
}
}
As far as the actual comparison logic goes, your question is not very specific about the exact rules you are using to compare two objects. However, from the example, I can kind of guess that these are your rules:
Compare the first number of each array.
If they are equal, repeat this process using the next number of each array.
Otherwise, the result of this comparison is the final result.
You don't really specify what to do if one array is shorter than the other. I'll leave writing the actual algorithm to you (although others answers appear to have done that for you). However, I will point out that because values is a private field, you won't be able to use that field for comparison unless you implement a getter for the field or make it public.
public int[] getValues() { return values; }
If your array is private and you do want to provide an accessor method then implement Comparable for the class and do something like below code.
If you have an accessor method then do this in a Comparator.
This code does not assume arrays to be of same size so it works for different size arrays. Please change according to your need.
PS - not compiled/tested
public int compareTo(Object o) {
CustomClass other = (CustomClass ) o;
int i = 0;
while (i <= numbers.length && i <= other.numbers.length) {
if (numbers[i] < other.numbers[i])
return -1;
else if (numbers[i] > other.numbers[i])
return 1;
++i;
}
if (numbers.length < other.numbers.length)
return -1;
else if (numbers.length > other.numbers.length)
return 1;
return 0;
}

Java int[] array to HashSet<Integer>

I have an array of int:
int[] a = {1, 2, 3};
I need a typed set from it:
Set<Integer> s;
If I do the following:
s = new HashSet(Arrays.asList(a));
it, of course, thinks I mean:
List<int[]>
whereas I meant:
List<Integer>
This is because int is a primitive. If I had used String, all would work:
Set<String> s = new HashSet<String>(
Arrays.asList(new String[] { "1", "2", "3" }));
How to easily, correctly and succinctly go from:
A) int[] a...
to
B) Integer[] a ...
Thanks!
Using Stream:
// int[] nums = {1,2,3,4,5}
Set<Integer> set = Arrays.stream(nums).boxed().collect(Collectors.toSet())
The question asks two separate questions: converting int[] to Integer[] and creating a HashSet<Integer> from an int[]. Both are easy to do with Java 8 streams:
int[] array = ...
Integer[] boxedArray = IntStream.of(array).boxed().toArray(Integer[]::new);
Set<Integer> set = IntStream.of(array).boxed().collect(Collectors.toSet());
//or if you need a HashSet specifically
HashSet<Integer> hashset = IntStream.of(array).boxed()
.collect(Collectors.toCollection(HashSet::new));
Some further explanation. The asList method has this signature
public static <T> List<T> asList(T... a)
So if you do this:
List<Integer> list = Arrays.asList(1, 2, 3, 4)
or this:
List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3, 4 })
In these cases, I believe java is able to infer that you want a List back, so it fills in the type parameter, which means it expects Integer parameters to the method call. Since it's able to autobox the values from int to Integer, it's fine.
However, this will not work
List<Integer> list = Arrays.asList(new int[] { 1, 2, 3, 4} )
because primitive to wrapper coercion (ie. int[] to Integer[]) is not built into the language (not sure why they didn't do this, but they didn't).
As a result, each primitive type would have to be handled as it's own overloaded method, which is what the commons package does. ie.
public static List<Integer> asList(int i...);
Or you could easly use Guava to convert int[] to List<Integer>:
Ints.asList(int...)
asList
public static List<Integer> asList(int... backingArray)
Returns a fixed-size list backed by the specified array, similar to Arrays.asList(Object[]). The list supports List.set(int, Object), but any attempt to set a value to null will result in a NullPointerException.
The returned list maintains the values, but not the identities, of Integer objects written to or read from it. For example, whether list.get(0) == list.get(0) is true for the returned list is unspecified.
You can use ArrayUtils in Apache Commons:
int[] intArray = { 1, 2, 3 };
Integer[] integerArray = ArrayUtils.toObject(intArray);
Another option would be to use a primitive set from Eclipse Collections. You can easily convert an int[] to a MutableIntSet to a Set<Integer> or Integer[] as shown below, or you can use the MutableIntSet as is which will be much more memory efficient and performant.
int[] a = {1, 2, 3};
MutableIntSet intSet = IntSets.mutable.with(a);
Set<Integer> integerSet = intSet.collect(i -> i); // auto-boxing
Integer[] integerArray = integerSet.toArray(new Integer[]{});
If you want to go directly from the int array to the Integer array and preserve order, then this will work.
Integer[] integers =
IntLists.mutable.with(a).collect(i -> i).toArray(new Integer[]{});
Note: I am a committer for Eclipse Collections
Just add elements from array to Set with the below snippet
public class RemoveDuplicateElements {
public static void main(String args[]){
int array[] = {0,1,2,3,4,5,6,7,8,9,1,2,3,4,5};
Set <Integer> abc = new HashSet <Integer>();
for (Integer t:array){
abc.add(t);
}
System.out.println("sampleSet"+abc);
}
}
No need for looping :
Just you will convert the array to a List
Then converting this List to a hash set.
Ex:
List list = Arrays.asList(your_array);
Set set = new HashSet<>(list);
This worked perfect for me .

Java: Is there any short combination to convert array of primitive to List & receive "printable" version?

int[] arrc = new int[] {1, 2, 3};
System.out.println(new ArrayList(Arrays.asList(arrc)));
prints address, but i desire to use toString as in ArrayList.
Is it possible ?
Try:
import java.util.Arrays;
// ...
int[] arrc = new int[] {1, 2, 3};
System.out.println(Arrays.toString(arrc));
Note that the asList(...) does not take an array of primitive int's but takes Objects instead, that's why you see an address-like String appear.
So, doing:
int[] array = {1, 2, 3};
List list = Arrays.asList(array);
results in the same as doing:
int[] array = {1, 2, 3};
List list = new ArrayList();
list.add(array);
Both result in a List that has one element in it: an array of primitive ints.
(only that Arrays.asList(...) returns a List that cannot be modified...)
If you just want to print the array:
Arrays.toString( arrc )
If you want to turn an int[] into a List, Arrays.asList does not work, unfortunately (it only works with Object[]):
List<Integer> list = new ArrayList<Integer>(arrc.length);
for (int a: arrc)
list.add(a);
System.out.println(list); // prints nicely now
use Arrays.toString(arrc)
Use Apache Commons Lang as your main library after SDK
System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
using Dollar should be simple:
int[] ary = { 1, 2, 3, 4};
String string = $(ary).toString(); // wrapping Arrays.toString()
alternatively you can convert the int array to List then use the toString method :
List<Integer> list = $(ary).toList();
please note that list is an ArrayList: you can even specify which concrete class should be used simply passing a List implementation (it will work with any List implementation with a no-args constructor):
List<Integer> linkedList = $(ary).toList(LinkedList.class);
Using Ints.asList from Guava:
import java.util.List;
import com.google.common.primitives.Ints;
// ...
int[] arrc = {1, 2, 3, 4};
List<Integer> list = Ints.asList(arrc);
System.out.println(list);
// Output: "[1, 2, 3, 4]"

Categories