Suppose the user enter an array, for example:
Array = {France, Spain, France, France, Italy, Spain, Spain, Italy}
which I did know the length of it
the index array would be:
index = {0, 1, 2, 3, 4, 5, 6, 7}
Now, after sorting it using Arrays.sort(Array);
newArray will be like:
newArray = {France, France, France, Italy, Italy, Spain, Spain, Spain}
and the newIndex will be:
newIndex = {0, 2, 3, 4, 7, 1, 5, 6}
The problem is: how can I find the newIndex from the input Array?
Don't sort the array to start with. Sort the index array, passing in a comparator which compares values by using them as indexes into the array. So you end up with newIndex as the result of the sort, and it's trivial to go from there to the sorted array of actual items.
Admittedly that means sorting an array of integers in a custom way - which either means using an Integer[] and the standard Java library, or a 3rd party library which has an "IntComparator" interface which can be used in conjunction with a sort(int[], IntComparator) type of method.
EDIT: Okay, here's an example comparator. For the sake of simplicity I'll assume you only want to sort an "original" array of strings... and I won't bother with nullity testing.
public class ArrayIndexComparator implements Comparator<Integer>
{
private final String[] array;
public ArrayIndexComparator(String[] array)
{
this.array = array;
}
public Integer[] createIndexArray()
{
Integer[] indexes = new Integer[array.length];
for (int i = 0; i < array.length; i++)
{
indexes[i] = i; // Autoboxing
}
return indexes;
}
#Override
public int compare(Integer index1, Integer index2)
{
// Autounbox from Integer to int to use as array indexes
return array[index1].compareTo(array[index2]);
}
}
You'd use it like this:
String[] countries = { "France", "Spain", ... };
ArrayIndexComparator comparator = new ArrayIndexComparator(countries);
Integer[] indexes = comparator.createIndexArray();
Arrays.sort(indexes, comparator);
// Now the indexes are in appropriate order.
Concise way of achieving this with Java 8 Stream API,
final String[] strArr = {"France", "Spain", "France"};
int[] sortedIndices = IntStream.range(0, strArr.length)
.boxed().sorted((i, j) -> strArr[i].compareTo(strArr[j]) )
.mapToInt(ele -> ele).toArray();
TreeMap<String,Int> map = new TreeMap<String,Int>();
for( int i : indexes ) {
map.put( stringarray[i], i );
}
Now iterator over map.values() to retrieve the indexes in sort order, and over map.keySet() to get the strings, or over map.entrySet() to get the String-index-Pairs.
If having a scenario of repeatedly sorting primitive float or int arrays with positive values, then a method like below yields much better (x3~x4) speed compared to using any comparators:
long time = System.currentTimeMillis();
for (int i = 0; i < iters; i++) {
float[] array = RandomUtils.randomFloatArray(-1, 1, 3000);
long[] valueKeyPairs = new long[array.length];
for (int j = 0; j < array.length; ++j) {
valueKeyPairs[j] = (((long) Float.floatToIntBits(array[j])) << 32) | (j & 0xffffffffL);
}
Arrays.sort(valueKeyPairs);
/**Then use this to retrieve the original value and index*/
//long l = valueKeyPairs[j];
//float value = Float.intBitsToFloat((int) (l >> 32));
//int index = (int) (l);
}
long millis = System.currentTimeMillis() - time;
I made the following based on #Skeet's code. I think it is a little more OOPie. I dunno.
public static <T extends Comparable<T>> List<Integer> sortIndex(List<T> in) {
ArrayList<Integer> index = new ArrayList<>();
for (int i = 0; i < in.size(); i++) {
index.add(i);
}
Collections.sort(index, new Comparator<Integer>() {
#Override
public int compare(Integer idx1, Integer idx2) {
return in.get(idx1).compareTo(in.get(idx2));
}
});
return index;
}
Instead of the class that implements the sorting and indexing having the Comparator code for the different objects coming in, the objects in the original array must implement the Comparable interface. It seems many objects of interest have a natural ordering and have the Comparable interface implemented already.
public static void main(String[] args) {
List<Integer> a1 = new ArrayList<>(Arrays.asList(2, 3, 9, 4, 1));
// Just pass in the list to have its indexes sorted by the natural ordering
List<Integer> idx = sortIndex(a1);
List<Double> a2 = new ArrayList<>(Arrays.asList(1.0, 5.3, 5.2, -3.1, 0.3));
idx = sortIndex(a2);
List<numBits> a3 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
a3.add(new numBits(i));
}
// If you need to sort the indexes of your own object, you must implement
// the Comparable Interface.
idx = sortIndex(a3);
}
static class numBits implements Comparable<numBits> {
private int a;
public numBits(int i) {
a = i;
}
public String toString() {
return Integer.toString(a);
}
// Sort by the total number of bits in the number.
#Override
public int compareTo(numBits that) {
if (Integer.bitCount(this.a) < Integer.bitCount(that.a))
return -1;
if (Integer.bitCount(this.a) > Integer.bitCount(that.a))
return 1;
return 0;
}
}
One way you could do this is to Wrap the original index and country name into a separate Class. Then sort the Array based on the names. This way, your original indexes will be preserved.
What Comes at first Glance is Map them like that
Map <Integer, String> map = new HashMap<Integer, String>();
map.put(0, "France");
map.put(1, "Spain");
map.put(2, "France");
and then sort them by value like that and then you can know their indexes and values (key, values) just print the map
Iterator mapIterator = map.keySet().iterator();
while (mapIterator .hasNext()) {
String key = mapIterator.next().toString();
String value = map.get(key).toString();
System.out.println(key + " " + value);
}
i found solution.
List<String> a = {b, a, d, c};
List<Integer> b = {2, 1, 4, 3};
and if a sort
private void setsortb() {
List<String> beforeA = new ArrayList<>();
List<Integer> beforeB = new ArrayList<>();
beforeA.addAll(a);
beforeB.addAll(b);
a.sort();//change like this {a, b, c, d}
for(int i = 0; i < beforeA.size(); i++) {
int index = beforeA.indexOf(a.get(i));
b.set(i, beforeB.get(i));
}
}
like this
result
a = {a, b, c, d}
b = {1, 2, 3, 4}
Related
I have got two arraylists :
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(0);
numbers.add(0);
numbers.add(8);
ArrayList<String> linkers = new ArrayList<>();
linkers.add("five");
linkers.add("two");
linkers.add("zero");
linkers.add("zero");
linkers.add("eight");
I need to sort the numbers list in ascending order and get the linkers list sorted in the same order.
Assuming there is a one-to-one mapping of the number to their name you can do it like so. Just sort the indices based on the list of numeric numbers. Then use those indices to get each list's values in the proper, sorted order. Here, I just print them to show the results.
List<Integer> indices = IntStream.range(0, numbers.size()).boxed()
.sorted(Comparator.comparing(numbers::get)).toList();
for (int i : indices) {
System.out.println(numbers.get(i) + " " + linkers.get(i));
}
prints
0 zero
0 zero
2 two
5 five
8 eight
They could be "sorted" as follows:
numbers = indices.stream().map(numbers::get).toList();
linkers = indices.stream().map(linkers::get).toList();
System.out.println(numbers);
System.out.println(linkers);
prints
[0, 0, 2, 5, 8]
[zero, zero, two, five, eight]
Parallel lists/arrays are trouble. Put corresponding elements into combined objects, then sort those.
import java.util.ArrayList;
import java.util.Comparator;
class Pair {
public int i;
public String s;
public Pair(int _i, String _s) {
i = _i;
s = _s;
}
}
class Test {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(0);
numbers.add(0);
numbers.add(8);
ArrayList<String> linkers = new ArrayList<>();
linkers.add("five");
linkers.add("two");
linkers.add("zero");
linkers.add("zero");
linkers.add("eight");
ArrayList<Pair> pairs = new ArrayList<>();
for (int i = 0; i < 5; i++) {
pairs.add(new Pair(numbers.get(i), linkers.get(i)));
}
pairs.sort(new Comparator<Pair>() {
public int compare(Pair a, Pair b) {
if (a.i == b.i) return 0;
else if (a.i < b.i) return -1;
else return 1;
}
});
for (int i = 0; i < 5; i++) {
System.out.println(pairs.get(i).s);
}
}
}
One possibility would be to group each number (int) with its name (String) in a class (Java < 15) or record (Java >= 15):
record NumberWithName(int value, String name) {
}
Then, for each pair of int and String from the two Lists, construct a Number-instance and add it to a new List numbersWithName:
List<Integer> values = List.of(5, 2, 0, 0, 8);
List<String> names = List.of("five", "two", "zero", "zero", "eight");
List<NumberWithName> numbersWithName = new ArrayList<>();
for (int index = 0; index < values.size(); ++index) {
numbersWithName.add(new NumberWithName(values.get(index), names.get(index)));
}
Finally, we sort this List with a corresponding Comparator and print the result:
numbersWithName.sort(Comparator.comparing(NumberWithName::value));
System.out.println(numbersWithName);
This produces the following output:
[NumberWithName[value=0, name=zero], NumberWithName[value=0, name=zero], NumberWithName[value=2, name=two], NumberWithName[value=5, name=five], NumberWithName[value=8, name=eight]]
A TreeMap should help here where your key is the integer and the value represents the string. TreeMap is directly sorted by the key.
I have two arrays, one stores the distance of the cities and the other stores the corresponding population. Everything works fine if the distance of the cities is in ascending order.
But let say if someone inputs the distance randomly. How can I sort the cities array and also make sure that the population of the respective city is in the same index as the index of its respective city population.
For example:
City 1 has population 333
City 3 has population 33333
City 5 has population 33
int[] city = {1, 3, 5};
int[] pop = {333, 33333, 33};
Everything works fine because the city array is sorted already.
But when I input:
int[] city = {3, 1, 5};
int[] pop = {3333, 333, 33};
Big problem!
I want sort the array city and make sure that the population array has all its elements at the same index as their respective city.
The good way of doing this is having a city class:
class City{
private int id;
private long population;
//... getters, setters, etc
}
a city comparator class:
class CityPopulationComparator implements Comparator<City> {
#Override
public int compare(City c1, City c2) {
return Long.compare(c1.getPopulation(), c2.getPopulation());
}
}
And an array list of cities:
ArrayList<City> cities;
and finally sort it using:
Collections.sort(cities, new CityPopulationComparator());
But if you need to have your cities and populations this way, you can write a sort method yourself (a bubble sort for example) and whenever you swap two cities, also swap corresponding pupulations.
The correct solution is this. However if you want a completely mad hack, you can do this:
public final class ParallelIntArrays extends AbstractList<int[]> {
private final int[] array1;
private final int[] array2;
public ParallelIntArrays(int[] array1, int[] array2) {
if (array1.length != array2.length)
throw new IllegalArgumentException();
this.array1 = array1;
this.array2 = array2;
}
#Override
public int[] get(int i) {
return new int[] { array1[i], array2[i] };
}
#Override
public int size() {
return array1.length;
}
#Override
public int[] set(int i, int[] a) {
if (a.length != 2)
throw new IllegalArgumentException();
int[] b = get(i);
array1[i] = a[0];
array2[i] = a[1];
return b;
}
}
Then you can do:
int[] city = {5, 1, 2, 4, 3 };
int[] pop = {100, 30, 4000, 400, 5000};
new ParallelIntArrays(city, pop).sort(Comparator.comparingInt(arr -> arr[0]));
System.out.println(Arrays.toString(city));
System.out.println(Arrays.toString(pop));
Note that as written above, ParallelIntArrays does not function correctly as a List. For example list.contains(list.get(0)) would give false. If you made it a List<IntBuffer> or a List<List<Integer>> instead, it would be fixed.
If your city id is unique:
int[] city = { 3, 1, 5};
int[] pop = {3333, 333, 33};
Map<Integer, Integer> arr = new HashMap<>(city.length);
for (int i = 0; i < city.length; i++) {
arr.put(city[i], pop[i]);
}
Arrays.sort(city);
for (int i = 0; i < city.length; i++) {
pop[i] = arr.get(city[i]);
}
The same using SortedMap
int[] city = { 3, 1, 5};
int[] pop = {3333, 333, 33};
SortedMap<Integer, Integer> arr = new TreeMap<>();
for (int i = 0; i < city.length; i++) {
arr.put(city[i], pop[i]);
}
System.out.println(arr.keySet());
System.out.println(arr.values());
A "cheap" way would be to have a third array which would contain 0 to n representing the index of the other arrays
But the problem you are having would disappear if they were grouped in a class, both information seem logically related.
Then you would implement Comparable: https://stackoverflow.com/a/18896422
You can collect a third array containing pairs of elements of these two arrays and sort it. Then you can iterate over this array and replace the elements of the first two arrays:
int[] city = {3, 1, 5};
int[] pop = {333, 33333, 33};
int[][] sorted = IntStream.range(0, city.length)
// Stream<int[]>
.mapToObj(i -> new int[]{city[i], pop[i]})
// sort by city
.sorted(Comparator.comparing(arr -> arr[0]))
.toArray(int[][]::new);
// replace the elements of the first two arrays
IntStream.range(0, sorted.length).forEach(i -> {
city[i] = sorted[i][0];
pop[i] = sorted[i][1];
});
System.out.println(Arrays.toString(city)); // [1, 3, 5]
System.out.println(Arrays.toString(pop)); // [33333, 333, 33]
See also: How do I sort two arrays in relation to each other?
public static void main(String[] args) {
Integer[] bidAmount = {3000, 54000, 2000, 1000, 5600};
String[] bidderName = {"Jenny", "Mike", "Alvin", "Berry", "John"};
Map<Integer, String> stringTreeMap = new TreeMap<>();
stringTreeMap.put(bidAmount[0], bidderName[0]);
stringTreeMap.put(bidAmount[1], bidderName[1]);
stringTreeMap.put(bidAmount[2], bidderName[2]);
stringTreeMap.put(bidAmount[3], bidderName[3]);
stringTreeMap.put(bidAmount[4], bidderName[4]);
for (Map.Entry<Integer, String> entry : stringTreeMap.entrySet()) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " => " + value);
}
}
I have code for a MergeSort of generic arrays. The only problem is, that I want the output to be with the index instead of the actual int, float or whatever. Do you guys have any idea on how to do that?
Here is the code I have so far:
class MergeSortGeneric<T extends Comparable<? super T>> {
public static void main(String[] args)
{
// example using Strings
String[] arrayOfStrings = {"Andree", "Leana", "Faviola", "Loyce", "Quincy",
"Milo", "Jamila", "Toccara", "Nelda", "Blair", "Ernestine", "Chara", "Kareen", "Monty", "Rene",
"Cami", "Winifred", "Tara", "Demetrice", "Azucena"};
MergeSortGeneric<String> stringSorter = new MergeSortGeneric<>();
stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);
System.out.println(java.util.Arrays.toString(arrayOfStrings));
// example using Doubles
Double[] arrayOfDoubles = {0.35, 0.02, 0.36, 0.82, 0.27, 0.49, 0.41, 0.17, 0.30,
0.89, 0.37, 0.66, 0.82, 0.17, 0.20, 0.96, 0.18, 0.25, 0.37, 0.52};
MergeSortGeneric<Double> doubleSorter = new MergeSortGeneric<>();
doubleSorter.mergeSort(arrayOfDoubles, 0, arrayOfDoubles.length - 1);
System.out.println(java.util.Arrays.toString(arrayOfDoubles));
}
// main function that sorts array[start..end] using merge()
void mergeSort(T[] array, int start, int end)
{
// base case
if (start < end)
{
// find the middle point
int middle = (start + end) / 2;
mergeSort(array, start, middle); // sort first half
mergeSort(array, middle + 1, end); // sort second half
// merge the sorted halves
merge(array, start, middle, end);
}
}
// merges two subarrays of array[].
void merge(T[] array, int start, int middle, int end)
{
T[] leftArray = (T[]) new Comparable[middle - start + 1];
T[] rightArray = (T[]) new Comparable[end - middle];
// fill in left array
for (int i = 0; i < leftArray.length; ++i)
leftArray[i] = array[start + i];
// fill in right array
for (int i = 0; i < rightArray.length; ++i)
rightArray[i] = array[middle + 1 + i];
/* Merge the temp arrays */
// initial indexes of first and second subarrays
int leftIndex = 0, rightIndex = 0;
// the index we will start at when adding the subarrays back into the main array
int currentIndex = start;
// compare each index of the subarrays adding the lowest value to the currentIndex
while (leftIndex < leftArray.length && rightIndex < rightArray.length)
{
if (leftArray[leftIndex].compareTo(rightArray[rightIndex]) <= 0)
{
array[currentIndex] = leftArray[leftIndex];
leftIndex++;
}
else
{
array[currentIndex] = rightArray[rightIndex];
rightIndex++;
}
currentIndex++;
}
// copy remaining elements of leftArray[] if any
while (leftIndex < leftArray.length) array[currentIndex++] = leftArray[leftIndex++];
// copy remaining elements of rightArray[] if any
while (rightIndex < rightArray.length) array[currentIndex++] = rightArray[rightIndex++];
}
}
thank you guys for any tips. Thats the task by the way:
Implement the Merge-Sort algorithm. The algorithm sorts a java.util.list
of any elements. Therefore the class must be generic. For sorting it gets a
matching comparator.
var data = Arrays.asList(23, 42, 11, 1, 12);
var mergeSort = new MergeSort<Integer>();
mergeSort.setup(data, (i1, i2) -> i1 - i2);
However, the element positions in the input list are not changed. Instead, the
specifies the sorting by a permutation array. The array has as many in-elements as
the input data list has elements. Each τ element specifies the index of the corresponding input element after sorting. Also internally you use only permutation arrays and no
further lists of input elements.
The easiest way without modifying the merge algorithm you be:
Create a copy of the arrays to be sorted;
Sort the arrays;
Compare the copy and the sorted array and figure it out the index.
For example:
String[] arrayOfStrings = {...};
List<String> copyArrayOfStrings = Arrays.stream(arrayOfStrings).collect(Collectors.toList());
...
stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);
...
List<Integer> index = Arrays.stream(arrayOfStrings).map(copyArrayOfStrings::indexOf).collect(Collectors.toList());
System.out.println(java.util.Arrays.toString(index.toArray()));
If for some strange reason you can only use arrays, and basic operators, the aforementioned logic still holds true:
the copy:
String[] copyArrayOfStrings = new String[arrayOfStrings.length];
for(int i = 0; i < arrayOfStrings.length; i++){
copyArrayOfStrings[i] = arrayOfStrings[i];
}
the sorting:
stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);
getting the indexes:
Integer[] index = new Integer[copyArrayOfStrings.length];
int index_pos = 0;
for(String s : arrayOfStrings) {
for (int i = 0; i < copyArrayOfStrings.length; i++) {
if(copyArrayOfStrings[i].equals(s)){
index[index_pos++] = i;
break;
}
}
}
System.out.println(java.util.Arrays.toString(index));
You can use a lambda compare, if the indexes are Integer types as opposed to native ints. Only the array of indices needs to be Integer type, the array of values can be primitive type.
package x;
import java.util.Arrays;
public class x {
public static void main(String[] args) {
int[] A = {3, 1, 2, 0};
Integer[] I = {0, 1, 2, 3};
Arrays.sort(I, (i, j) -> A[i]-A[j]);
for (Integer i : I) {
System.out.println(A[i]);
}
}
}
you can create a class like below (note it is pseudo code)
import java.util.Arrays;
public class SomeClass {
public static void main(String[] args) {
double[] doubleArray = new double[] {2.3, 3.4, 1.2, 0.3, 4.3};
ObjectWithIndex[] objectWithIndexAr = new ObjectWithIndex[doubleArray.length];
for (int i = 0; i < doubleArray.length; i++) {
objectWithIndexAr[i] = new ObjectWithIndex(i, doubleArray[i]);
}
Arrays.sort(objectWithIndexAr);
for ( ObjectWithIndex obj : objectWithIndexAr) {
System.out.println("index: " + obj.index + " value: " + obj.actualObject);
}
}
}
class ObjectWithIndex implements Comparable<ObjectWithIndex> {
int index;
Comparable actualObject;
public ObjectWithIndex(int index, Comparable object) {
this.index = index;
this.actualObject = object;
}
#Override
public int compareTo(ObjectWithIndex o) {
return this.actualObject.compareTo(o.actualObject);
}
}
you can create array of this object using your input array of Double, Integer (whatever implements Comparable) and sort the new array of ObjectWithIndex.
once sorted, you can print the index (which will have original index from your input)
I have already read a few other stack overflow threads on this:
to find the intersection of two multisets in java
How do I get the intersection between two arrays as a new array?
public static int[] intersection (int [] x, int numELementsInX, int [] y, int numElementsInY) {
I am trying to examine two arrays as well as their number of elements (numElementsInX and numElementsInY), and return a new array which contains the common values of array x and y. Their intersection.
Example,if x is{1,3,5,7,9}and y is{9,3,9,4} then
intersection(x, 5, y, 4} should return {3, 9} or {9, 3}
I've read I need to use the LCS algorithm. Can anyone give me an example as to how to do this? Both the array and values in array are initialized and generated in another method, then passed into intersection.
Any help/clarification is appreciated.
EDIT CODE
for (int i=0; i<numElementsInX; i++){
for (int j=0; j<numElementsInY; j++){
if (x[j]==x[i]) { //how to push to new array?;
}
else{
}
}
}
The simplest solution would be to use sets, as long as you don't care that the elements in the result will have a different order, and that duplicates will be removed. The input arrays array1 and array2 are the Integer[] subarrays of the given int[] arrays corresponding to the number of elements that you intend to process:
Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(array1));
Set<Integer> s2 = new HashSet<Integer>(Arrays.asList(array2));
s1.retainAll(s2);
Integer[] result = s1.toArray(new Integer[s1.size()]);
The above will return an Integer[], if needed it's simple to copy and convert its contents into an int[].
If you are fine with java-8, then the simplest solution I can think of is using streams and filter. An implementation is as follows:
public static int[] intersection(int[] a, int[] b) {
return Arrays.stream(a)
.distinct()
.filter(x -> Arrays.stream(b).anyMatch(y -> y == x))
.toArray();
}
General test
The answers provide several solutions, so I decided to figure out which one is the most effective.
Solutions
HashSet based by Óscar López
Stream based by Bilesh Ganguly
Foreach based by Ruchira Gayan Ranaweera
HashMap based by ikarayel
What we have
Two String arrays that contain 50% of the common elements.
Every element in each array is unique, so there are no duplicates
Testing code
public static void startTest(String name, Runnable test){
long start = System.nanoTime();
test.run();
long end = System.nanoTime();
System.out.println(name + ": " + (end - start) / 1000000. + " ms");
}
With use:
startTest("HashMap", () -> intersectHashMap(arr1, arr2));
startTest("HashSet", () -> intersectHashSet(arr1, arr2));
startTest("Foreach", () -> intersectForeach(arr1, arr2));
startTest("Stream ", () -> intersectStream(arr1, arr2));
Solutions code:
HashSet
public static String[] intersectHashSet(String[] arr1, String[] arr2){
HashSet<String> set = new HashSet<>(Arrays.asList(arr1));
set.retainAll(Arrays.asList(arr2));
return set.toArray(new String[0]);
}
Stream
public static String[] intersectStream(String[] arr1, String[] arr2){
return Arrays.stream(arr1)
.distinct()
.filter(x -> Arrays.asList(arr2).contains(x))
.toArray(String[]::new);
}
Foreach
public static String[] intersectForeach(String[] arr1, String[] arr2){
ArrayList<String> result = new ArrayList<>();
for(int i = 0; i < arr1.length; i++){
for(int r = 0; r < arr2.length; r++){
if(arr1[i].equals(arr2[r]))
result.add(arr1[i]);
}
}
return result.toArray(new String[0]);
}
HashMap
public static String[] intersectHashMap(String[] arr1, String[] arr2){
HashMap<String, Integer> map = new HashMap<>();
for (int i = 0; i < arr1.length; i++)
map.put(arr1[i], 1);
ArrayList<String> result = new ArrayList<>();
for(int i = 0; i < arr2.length; i++)
if(map.containsKey(arr2[i]))
result.add(arr2[i]);
return result.toArray(new String[0]);
}
Testing process
Let's see what happens if we give the methods an array of 20 elements:
HashMap: 0.105 ms
HashSet: 0.2185 ms
Foreach: 0.041 ms
Stream : 7.3629 ms
As we can see, the Foreach method does the best job. But the Stream method is almost 180 times slower.
Let's continue the test with 500 elements:
HashMap: 0.7147 ms
HashSet: 4.882 ms
Foreach: 7.8314 ms
Stream : 10.6681 ms
In this case, the results have changed dramatically. Now the most efficient is the HashMap method.
Next test with 10 000 elements:
HashMap: 4.875 ms
HashSet: 316.2864 ms
Foreach: 505.6547 ms
Stream : 292.6572 ms
The fastest is still the HashMap method. And the Foreach method has become quite slow.
Results
If there are < 50 elements, then it is best to use the Foreach method. He strongly breaks away in speed in this category.
In this case, the top of the best will look like this:
Foreach
HashMap
HashSet
Stream - Better not to use in this case
But if you need to process big data, then the best option would be use the HashMap based method.
So the top of the best look like this:
HashMap
HashSet
Stream
Foreach
With duplicate elements in array finding intersection.
int [] arr1 = {1,2,2,2,2,2,2,3,6,6,6,6,6,6,};
int [] arr2 = {7,5,3,6,6,2,2,3,6,6,6,6,6,6,6,6,};
Arrays.sort(arr1);
Arrays.sort(arr2);
ArrayList result = new ArrayList<>();
int i =0 ;
int j =0;
while(i< arr1.length && j<arr2.length){
if (arr1[i]>arr2[j]){
j++;
}else if (arr1[i]<arr2[j]){
i++;
}else {
result.add(arr1[i]);
i++;
j++;
}
}
System.out.println(result);
If you don't want to use other data structures such as a Set, then the basic idea is that you want to iterate through the elements of one of the arrays and for each value see if it appears in the other. How do you see whether it appears in the other array? Walk through the elements in the other array and for each one, see if its value is equal to the value you are looking for. I suspect that you will be best served by trying to work through this problem on your own beyond this point if your goal in taking the class is to learn to write Java well, but it you get stuck you might consider updating your question with the code that you have written so you can get more detailed feedback and pointers in the right direction.
Try this:
public static void main(String[] args) {
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] arr2 = new int[]{3, 2, 5, 9, 11};
getIntersection(arr1, arr2);
}
public static Object[] getIntersection(int[] arr1, int[] arr2) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
list.add(arr1[i]);
}
}
}
return list.toArray();
}
You can find the intersection of two arrays with:
T[] result = Arrays.stream(a1)
.filter(new HashSet<>(Arrays.asList(a2))::contains)
.toArray(T[]::new);
where T should be substitutable by a reference type e.g. String, Integer, etc.
although the above may seem like it's creating a new set for each element, it's not the case at all. instead only one set instance is created.
The above code is equivalent to:
List<T> list = new ArrayList<>();
HashSet<T> container = new HashSet<>(Arrays.asList(a2));
for (T s : a1) {
if (container.contains(s)) list.add(s);
}
T[] result = list.toArray(new T[0]);
finding intersection includes duplicate using the hash map.
Output: 1 2 2 15 9 7 12
public static void main(String[] args) {
int[] arr1 = {1, 2, 2, 1, 5, 9, 15, 9, 7, 7, 12};
int[] arr2 = {1, 2, 2, 3, 4, 15, 9, 7, 12, 14};
printIntersect(arr1, arr2);
}
private static void printIntersect(int[] arr1, int[] arr2) {
Map<Integer, Integer> map = new HashMap<>();
//put first array to map
for (int i = 0; i < arr1.length; i++) {
if (!map.containsKey(arr1[i])) {
map.put(arr1[i], 1);
} else {
map.put(arr1[i], map.get(arr1[i]) + 1);
}
}
//check all value in array two
for (int i = 0; i < arr2.length; i++) {
//if exist and value>1 then decrement value
//if value is 1 remove from map
if (map.containsKey(arr2[i])) {
System.out.print(arr2[i] + " ");
if (map.get(arr2[i]) > 1) {
map.put(arr2[i], map.get(arr2[i]) - 1);
} else {
map.remove(arr2[i]);
}
}
}
}
if the arrays are sorted
int a1[]=new int[] {1,2,3,5,7,8};
int a2[]=new int [] {1,5,6,7,8,9};
// get the length of both the array
int n1=a1.length;
int n2=a2.length;
//create a new array to store the intersection
int a3[]=new int[n1];
//run the loop and find the intersection
int i=0,j=0,k=0;
while(i<n1&& j<n2) {
if(a1[i]<a2[j]) {
// a1 element at i are smaller than a2 element at j so increment i
i++;
}else if(a1[i]>a2[j]) {
// a2 element at i are smaller than a2 element at j so increment j
j++;
}else {
// intersection element store the value and increment i, j, k to find the next element
a3[k]=a1[i];
i++;
j++;
k++;
}
}
for(int l=0;l<a3.length;l++) {
System.out.println(a3[l]);
}
How to Find the Intersection of 3 unsorted arrays in Java:-
I have used the Core Java approach using for loops & using Arrays.copyOf to achieve this.
public class Intersection {
public void intersection3Arrays(int ar1[], int ar2[], int ar3[]) {
Arrays. sort(ar1);
Arrays. sort(ar2);
Arrays. sort(ar3);
int ar1Len = ar1.length;
int ar2Len = ar2.length;
int ar3Len = ar3.length;
int larArray = ar3Len > (ar1Len > ar2Len ? ar1Len : ar2Len) ? ar3Len : ((ar1Len > ar2Len) ? ar1Len : ar2Len);
System.out.println("The largest array is " +larArray);
int[] inputArray1 = Arrays.copyOf(ar1, larArray);
int[] inputArray2 = Arrays.copyOf(ar2, larArray);
int[] inputArray3 = Arrays.copyOf(ar3, larArray);
Integer[] inputArray11 = new Integer[inputArray1.length];
Integer[] inputArray22 = new Integer[inputArray2.length];
Integer[] inputArray33 = new Integer[inputArray3.length];
for (int i = 0; i < inputArray11.length; i++) {
if (inputArray11[i] == null){
inputArray1[i] = 0;
}
}
for (int i = 0; i < inputArray22.length; i++) {
if (inputArray22[i] == null){
inputArray1[i] = 0;
}
}
for (int i = 0; i < inputArray33.length; i++) {
if (inputArray33[i] == null){
inputArray1[i] = 0;
}
}
for (int i = 0; i < inputArray11.length; i++)
for (int j = 0; j < inputArray22.length; j++)
for (int k = 0; k < inputArray33.length; j++)
if (inputArray11[i] == inputArray22[j] && inputArray11[i] == inputArray33[k]) {
System.out.print(inputArray11[i]+" ");
}
}
public static void main(String[] args) {
Intersection3Arrays arrays = new Intersection3Arrays();
int ar1[] = { 1, 2, 5, 10, 20, 40, 80 };
int ar2[] = { 80, 100, 6, 2, 7, 20 };
int ar3[] = {3, 4, 15, 20, 30, 70, 80, 120};
arrays.intersection3Arrays(ar1, ar2, ar3);
}
}
If you ever wanted to implement this in python, this is one way that you can find intersection.
#find intersection
def find_intersec(list_a, list_b):
return set(list_a).intersection(list_b)
#since lists are kind of like arrays in python we use two lists
list_a = [ 4, 9, 1, 17, 11, 26, 28, 10,28, 26, 66, 91]
list_b = [9, 9, 74, 21, 45, 11, 63,10]
print(find_intersec(list_a, list_b))
I hope this example will simple one.pass two arrays and you will definitely get INTERSECTION of array without duplicate items.
private static int[] findInterserctorOfTwoArray(int[] array1, int[] array2) {
Map<Integer,Integer> map=new HashMap<>();
for (int element : array1) {
for (int element2 : array2) {
if(element==element2) {
map.put(element, element);
}
}
}
int[] newArray=new int[map.size()];
int con=0;
for(Map.Entry<Integer, Integer> lst:map.entrySet()) {
newArray[con]=lst.getValue();
con++;
}
return newArray;
}
optimised for sorted arrays using only one loop.
int a1[]=new int[] {1,2,3,5,7,8};
int a2[]=new int [] {1,5,6,7,8,9};
// sort both the array
Arrays.sort(a1);
Arrays.sort(a2);
// get the length of both the array
int n1=a1.length;
int n2=a2.length;
//create a new array to store the intersection
int a3[]=new int[n1];
//run the loop and find the intersection
int i=0,j=0,k=0;
while(i<n1&& j<n2) {
if(a1[i]<a2[j]) {
// a1 element at i are smaller than a2 element at j so increment i
i++;
}else if(a1[i]>a2[j]) {
// a2 element at i are smaller than a2 element at j so increment j
j++;
}else {
// intersection element store the value and increment i, j, k to find the next element
a3[k]=a1[i];
i++;
j++;
k++;
}
}
for(int l=0;l<a3.length;l++) {
System.out.println(a3[l]);
}
Primitive Iterator: 6 Times Faster than HashSet
Tested on sorted arrays of 10,000,000 random elements, values between 0 and 200,000,000. Tested on 10 processor i9 with 4GB heap space. Sort time for two arrays was 1.9 seconds.
results:
primitive() - 1.1 seconds
public static int[] primitive(int[] a1, int[] a2) {
List<Integer> list = new LinkedList<>();
OfInt it1 = Arrays.stream(a1).iterator();
OfInt it2 = Arrays.stream(a2).iterator();
int i1 = it1.next();
int i2 = it2.next();
do {
if (i1==i2) {
list.add(i1);
i1 = it1.next();
}
if (i1 < i2) i1 = it1.next();
if (i2 < i1) i2 = it2.next();
} while(it1.hasNext() && it2.hasNext());
if (i1==i2) list.add(i1);
return list.stream().mapToInt(Integer::intValue).toArray();
}
boxed() - 6.8 seconds
public static int[] boxed(int[] a1, int[] a2) {
return Arrays.stream(a1)
.filter(new HashSet<>(Arrays.stream(a2).boxed()
.collect(Collectors.toList()))::contains)
.toArray();
}
I want to sort an array and find the index of each element in the sorted order.
So for instance if I run this on the array:
[3,2,4]
I'd get:
[1,0,2]
Is there an easy way to do this in Java?
Let's assume your elements are stored in an array.
final int[] arr = // elements you want
List<Integer> indices = new ArrayList<Integer>(arr.length);
for (int i = 0; i < arr.length; i++) {
indices.add(i);
}
Comparator<Integer> comparator = new Comparator<Integer>() {
public int compare(Integer i, Integer j) {
return Integer.compare(arr[i], arr[j]);
}
}
Collections.sort(indices, comparator);
Now indices contains the indices of the array, in their sorted order. You can convert that back to an int[] with a straightforward enough for loop.
import java.util.*;
public class Testing{
public static void main(String[] args){
int[] arr = {3, 2, 4, 6, 5};
TreeMap map = new TreeMap();
for(int i = 0; i < arr.length; i++){
map.put(arr[i], i);
}
System.out.println(Arrays.toString(map.values().toArray()));
}
}
One way to achieve this is to make a list of pairs with the starting index as the second part of the pair. Sort the list of pairs lexicographically, then read off the starting positions from the sorted array.
Starting array:
[3,2,4]
Add pairs with starting indexes:
[(3,0), (2,1), (4,2)]
Sort it lexicographically
[(2,1), (3,0), (4,2)]
then read off the second part of each pair
[1,0,2]
import java.io.*;
public class Sample {
public static void main(String[] args) {
int[] data = {0, 3, 2, 4, 6, 5, 10};//case:range 0 - 10
int i, rangeHigh = 10;
int [] rank = new int[rangeHigh + 1];
//counting sort
for(i=0; i< data.length ;++i) ++rank[data[i]];
for(i=1; i< rank.length;++i) rank[i] += rank[i-1];
for(i=0;i<data.length;++i)
System.out.print((rank[data[i]]-1) + " ");//0 2 1 3 5 4 6
}
}
As an update, this is relatively easy to do in Java 8 using the streams API.
public static int[] sortedPermutation(final int[] items) {
return IntStream.range(0, items.length)
.mapToObj(value -> Integer.valueOf(value))
.sorted((i1, i2) -> Integer.compare(items[i1], items[i2]))
.mapToInt(value -> value.intValue())
.toArray();
}
It somewhat unfortunately requires a boxing and unboxing step for the indices, as there is no .sorted(IntComparator) method on IntStream, or even an IntComparator functional interface for that matter.
To generalize to a List of Comparable objects is pretty straightforward:
public static <K extends Comparable <? super K>> int[] sortedPermutation(final List<K> items) {
return IntStream.range(0, items.size())
.mapToObj(value -> Integer.valueOf(value))
.sorted((i1, i2) -> items.get(i1).compareTo(items.get(i2)))
.mapToInt(value -> value.intValue())
.toArray();
}