Comparing and sorting in java - java

I have 2 arrays of data in Java. Based on the order of first array I have to sort the next array.
E.g -
String[] Array1 = {"EUROPE","MIDDLEEAST","OTHERs","AUSTRALIA"};
String[] Array2 = {"MIDDLEEAST","EUROPE","AUSTRALIA","OTHERs","ASIA","EUROPE"};
My output should look like:
{"EUROPE","EUROPE","MIDDLEEAST","OTHERs","AUSTRALIA","ASIA"}
What is the best way to do it?

To sort you need to define a sorting order so given element A and B, you can determine easily if A should go before or after B in the sorted list.
This concept is formalized with the concept of a Comparator in Java.
In this case the sorting order is defined by the order of the elements in a list. The simplest approach is given A and B to find each of them in the original list, note the index found, and compare the indexes to find out which one goes first.
Depending on the size of your data this might be too slow. You can then create a HashMap<String,Long> which holds the index of a given string in Array1. Here it would hold "DEF"->0, "ABC"->1, "XYZ"->2.

May be this:
1) Sort both of them.
2) Create blank result table
3) Take first elem from sorted Array2 and put it to result table with the original index of the first elem on sorted Array1
3) Repeat the step 3 on the second element and so on.
The computational complexity would be like sorting method used: O(nlogn) for quicksort

You can definitely do this in O(n log n). But the best approach depends on what is more important: quick, clean code or not allocating extra memory.
If you don't care about using extra memory, you can allocate a separate array, where each element is a pair:
public class Pair implements Comparable {
...
}
Then you would sort the array of pairs using Arrays.sort(Object[]).
If you don't want to allocate quite so much space, you can use an auxiliary array that contains the indexes in Integer form:
final String[] array1 = ...;
final String[] array2 = ...;
assert array1.length == array2.length;
Comparator<Integer> c = new Comparator<Integer> {
int compare(Integer a, Integer b) {
return array1[a].compareTo(array1[b]);
}
};
Integer[] aux = new Integer[array1.length];
for (int i = 0; i < aux.length; ++i) { aux[i] = i; }
Arrays.sort(aux, c);
String[] result = new String[array1.length];
for (int i = 0; i < aux.length; ++i) {
result[i] = array2[aux[i]];
}
If you are trying to do the entire thing in-place and not allocate additional memory, then you will need to implement one of the n-log-n sort algorithms yourself...

There are (at least) two ways to sort one array and reorder a second array so corresponding elements still match. Both require constructing a third array and writing a custom comparison function.
Method 1
Define a custom object that contains one element of each array. (In your case, it might be a two-element String array.) Write a comparator (or implement Comparable) for the custom object that simply compares the elements from the first array. Build an array of the custom objects from the two input arrays, sort the third array, and then extract the results.
This is the method most commonly recommended for this problem.
Method 2
Construct an array of Integer indexes initialized to 0, 1, 2, ..., n-1 (where n == Array1.length). Sort the index array using a comparator that compares indexes by comparing the Array1 elements that they index.
The second method will be faster and will not require as much object construction.

Two other ideas:
Could these values be an enum rather than a set of strings? The natural order of an enum is the order of declaration, so Arrays.sort() would just work.
Helper code exists in Guava's Ordering.explicitOrder(List):
String[] explicitOrder = {"EUROPE", "MIDDLEEAST", "OTHERs", "AUSTRALIA"};
String[] toSort = ...
Comparator<String> comparator = Ordering.explicit(Arrays.asList(explicitOrder));
String[] sorted = Arrays.sort(toSort, comparator);

Related

Removing duplicates from sorted array list and return size in java without using extra space

Is there a better way to remove dups from the array list compared to the below code which does the work in O(n) when encountered with larger input. Any suggestions would be appreciated. Thank you.
Note :- Can't use any extra space and should be solved in place.
Input :- It will be a sorted array with dups.
Code :-
public int removeDuplicates(ArrayList<Integer> a) {
if(a.size()>1){
for( int i=0;i<a.size()-1;i++ ) {
if(a.get(i).intValue() == a.get(i+1).intValue() ) {
a.remove(i);
i--;
}
}
}
return a.size();
}
Please test the code here at coder pad link.
https://coderpad.io/MXNFGTJC
If this code is for removing elements of an unsorted list, then:
The algorithm is incorrect.
The Question is a duplicate of How do I remove repeated elements from ArrayList? (for example ...)
If the list is sorted, then:
The algorithm is correct.
The algorithm is NOT O(N). It is actually O(ND) on average where N is the list length and D is the number of duplicates.
Why? Because ArrayList::remove(int) is an on average O(N) operation!
There are two efficient ways to remove a large number of elements from a list:
Create a new list, iterate the old list and add the elements that you want to retain to the new list. Then either discard the old list or clear it and copy the new list to the old one.
This works efficiently (O(N)) for all standard kinds of list.
Perform a sliding window removal. The algorithm with arrays is like this:
int i = 0;
for (int j = 0; j < array.length; j++) {
if (should remove array[j]) {
// do nothing
} else {
array[i++] = array[j];
}
}
// trim array to length i, or assign nulls or something.
As you can see, this performs one pass through the array, and is O(N). It also avoids allocating any temporary space.
You can implement the sliding window removal using ArrayList::get(int) and ArrayList::set(int, <E>) ... followed by repeated removal of the last element to trim the list.
Here are some ideas to improve performance:
Removing elements one by one from an ArrayList can be expensive since you must shift the all contents after that element. Instead of ArrayList you might consider a different list implementation which allows O(1) removal. Alternatively, if you must use ArrayList and are not allowed any temporary data structures, you can rebuild the array by chaining together recursive calls that use set() instead of remove().
For lists with millions of elements, consider a parallel processing solution to leverage the power of multiple processes. Java streams are a simple way to achieve this.
List<Integer> l = new ArrayList<Integer>();
//add some elements to l
System.out.println(l.stream().distinct().collect(Collectors.toList()));

how to merge two sorted arrays of same size?

1st array: {3,5,6,9,12,14,18,20,25,28}
2nd array: {30,32,34,36,38,40,42,44,46,48}
Sample Output:
{3,5,6,9,12,14,18,20,25,28,30,32,34,36,38,40,42,44,46,48}
I have to merge 1st array into second array. 2nd array has space to accomadate all values
Whenever i know i need a collection to be sorted, i use a method that will insert new elements in right place, so the collection will never have state when its not sorted... in your case you might be good with adding two into destination collection then use Collections.sort() but you can do sortedInsert() as well... you can create your collection and start addin all items into it using this method, and when you finished you dont need another call to Collections.sort() because collection is always in sorted state... This is handy if you often do single element update and dont want whole collection to be resorted... this will work with much better performance...
Here is what i do for List
/**
* Inserts the value keeping collection sorted, provided collections shall be sorted with provided
* comparator
*/
public static <E> void sortedInsert(List<E> list, E value, Comparator<? super E> comparator) {
assert Ordering.from(comparator).isOrdered(list);
if (list.size() == 0) {
list.add(value);
} else if (comparator.compare(list.get(0), value) > 0) {
list.add(0, value);
} else if (comparator.compare(list.get(list.size() - 1), value) < 0) {
list.add(list.size(), value);
} else {
int i = 0;
while (comparator.compare(list.get(i), value) < 0) {
i++;
}
list.add(i, value);
}
}
Use System.arraycopy to append a1 to a2
System.arraycopy(a1, 0, a2, a2_len, a1.length);
then Arrays.sort
Use two pointers/counters, i & j starting from 0 to size of the array. Compare a[i] & b[j] and based on the result shift i or j (similar to merge sort, merging step). If extra space isn't allowed then in worst case (which is true in your input, all the elements in first array is smaller than first element in second array) you might have to shift 2nd array every time you compare elements.
Make a ArrayList object as arrayListObject
ArrayList<Integer> arrayListObject= new ArrayList<>();
Add elements of both arrays in that arrayListObject
Do Collectios.sort(arrayListObject) to sort the elements.
Use
Integer list2[] = new Integer[arrayListObject.size()];
list2 = arrayListObject.toArray(list2);
to get the resulted array

Common elements of muiltiple arrays but not using Lists

Is there a way i could return in an array the common elements of 2 or more arrays? I know having some of the methods under lists could do it but is there a way to do it by only using arrays? I made my own get and length btw since i am creating a an array called OrderedIntList.
Example would be:
1,3,5
1,6,7,9,3
1,3,10,11
Result: 1,3
I tried this and it outputs the common elements between two arrays and not all.
I know there's something wrong but i do not how to make it work like it suppose to work :(
//returns the common elements of inputted arrays
public static OrderedIntList common(OrderedIntList ... lists){
int[] list = new int[10];
for(int x = 1; x <= lists.length -1; x++){
for(int q = 0; q < lists[0].length()-1; q++) {
for(int z = 0; z < lists[x].length(); z++) {
if (lists[0].get(q)==lists[x].get(z)){
list[q] = lists[0].get(q);
}
}
}
}
OrderedIntList newlist = new OrderedIntList(list);
return newlist;
}
This can be an easy algorithm to solve it...
1) Instantiate an instance variable of type array called
"commonElements" pointing to the elements of the first Array. At the
beginning these are your common elements.
2) Create a method call getCommonElements(int[] commonElements,
int[] newList). This method manipulates the commonElements array to leave
it with only the common elements between the two. (p.s Use a temporary
array to achieve this if you find it easier)
3) Iterate over all the arrays present in "lists" starting from the
second array.
4) call the method at point 2 for each array .
All the difficult part for you it's to implement a method that given 2 arrays finds the common elements!
You can use
org.apache.commons.collections.CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
to get the intersection of two lists (elements presents in both lists)
And to pass your array as a Collection: java.util.Arrays.asList(Object[] a);
But working on arrays is tedious, at best. You should consider why you don't want to use a Collection...
As a partial answer, you're probably doing too much work by fully reimplementing an OrderedIntList the way you're doing, since ArrayList and friends already come with sorting baked in via the Collections class.
import java.util.Collections;
public class OrderedIntList extends ArrayList<Integer> {
#override // to effect sorted inserts
public void add(Integer i) {
this.add(i);
Collections.sort(this);
// done.
}
}
Wanting to do this for pure arrays is a nice exercise, but then you'll be better of implementing sorting properly with a quick sort (you can't websearch for a java implementation of that without getting a million results) or an insert sort (equally websearchable), and follow the same recipe.
any time you push a number into the array:
guess where the number goes (although that's optional),
insert the number,
resort your array if you know your guess wasn't perfect.

Alphabetically sorting an ArrayList<String> using .compareTo()

An assignment we have to do in school is alphabetically sort two different ArrayLists into a final arraylist that contains both of the lists elements lexicographically
For example...
ArrayList sent1 contains in alphabetical order [., adam, mark]
ArrayList sent2 contains in alphabetical order [., betsy, kyle, william]
ArrayList sent3 must contain all of the elements in both ArrayLists in alphabetical order.
I just can't seem to figure out how to do it. My instructor mentioned using a while loop, but I don't just understand how to code the process. Combining sent1 and sent2 into sent3 and then using Collections.sort(sent3) would make the process so much easier and more compact, but the goal of the lab is to practice the using of compareTo().
If each source list is already sorted, just look at the first element in each list, add the "lower" (alphabetically first) to the output list, and repeat.
It's pretty simple;
List<String> sent3 = new ArrayList<String>(sent1);
sent3.addAll(sent2);
Collections.sort(sent3, new Comparator<String>() {
public int compare(String a, String b) {
return a.compareTo(b); // usage here!
}
}
What you are looking for is to use 2 iterators and just merge these 2 lists.
I'll give you some pseudo code.
ArrayList sent1, sent2, sent3;
int i1, i2;
i1 = i2 = 0;
while (i1 < sent1.length() && i2 < sent2.length())
{
if (sent1[i2].compareTo(sent2[i1])
{
sent3.add(sent1[i2]);
i2++;
}else
{
sent3.add(sent1[i1]);
i21+;
}
}
while(i1 < sent1.length()) sent3.add(sent1[i1++]);
while(i2 < sent2.length()) sent3.add(sent2[i2++]);
Here each time will add to my sent3 the minimum of the first items in sent1 and sent2. And when I get one of this lists empty, I will just append the rest of other elements into the sent3.
I think that you can do this:
copy array1 and array2 to array3; then, sort array3. you don't know how to sort using compareTo() ? Check is java documentation.

Remove multiple elements from ArrayList

I have a bunch of indexes and I want to remove elements at these indexes from an ArrayList. I can't do a simple sequence of remove()s because the elements are shifted after each removal. How do I solve this?
To remove elements at indexes:
Collections.sort(indexes, Collections.reverseOrder());
for (int i : indexes)
strs.remove(i);
Or, using the Stream API from Java 8:
indexes.sort(Comparator.reverseOrder());
indexes.stream().mapToInt(i -> i).forEach(l::remove);
Sort the indices in descending order and then remove them one by one. If you do that, there's no way a remove will affect any indices that you later want to remove.
How you sort them will depend on the collection you are using to store the indices. If it's a list, you can do this:
List<Integer> indices;
Collections.sort(indices, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
//todo: handle null
return b.compareTo(a);
}
}
Edit
#aioobe found the helper that I failed to find. Instead of the above, you can use
Collections.sort(indices, Collections.reverseOrder());
I came here for removing elements in specific range (i.e., all elements between 2 indexes), and found this:
list.subList(indexStart, indexEnd).clear()
You can remove the elements starting from the largest index downwards, or if you have references to the objects you wish to remove, you can use the removeAll method.
you might want to use the subList method with the range of index you would like to remove and
then call clear() on it.
(pay attention that the second parameter is exclusive - for example in this case, I pass 2 meaning only index 0 and 1 will be removed.):
public static void main(String[] args) {
ArrayList<String> animals = new ArrayList<String>();
animals.add("cow");
animals.add("dog");
animals.add("chicken");
animals.add("cat");
animals.subList(0, 2).clear();
for(String s : animals)
System.out.println(s);
}
}
the result will be:
chicken
cat
You can remove the indexes in reverse order. If the indexes are in order like 1,2,3 you can do removeRange(1, 3).
I think nanda was the correct answer.
List<T> toRemove = new LinkedList<T>();
for (T t : masterList) {
if (t.shouldRemove()) {
toRemove.add(t);
}
}
masterList.removeAll(toRemove);
You can sort the indices as many said, or you can use an iterator and call remove()
List<String> list = new ArrayList<String>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
List<Integer> indexes = new ArrayList<Integer>();
indexes.add(2);
indexes.add(5);
indexes.add(3);
int cpt = 0;
Iterator<String> it = list.iterator();
while(it.hasNext()){
it.next();
if(indexes.contains(cpt)){
it.remove();
}
cpt++;
}
it depends what you need, but the sort will be faster in most cases
Use guava! The method you are looking is Iterators.removeAll(Iterator removeFrom, Collection elementsToRemove)
If you have really many elements to remove (and a long list), it may be faster to iterate over the list and add all elements who are not to be removed to a new list, since each remove()-step in a array-list copies all elements after the removed one by one. In this case, if you index list is not already sorted (and you can iterate over it parallel to the main list), you may want to use a HashSet or BitSet or some similar O(1)-access-structure for the contains() check:
/**
* creates a new List containing all elements of {#code original},
* apart from those with an index in {#code indices}.
* Neither the original list nor the indices collection is changed.
* #return a new list containing only the remaining elements.
*/
public <X> List<X> removeElements(List<X> original, Collection<Integer> indices) {
// wrap for faster access.
indices = new HashSet<Integer>(indices);
List<X> output = new ArrayList<X>();
int len = original.size();
for(int i = 0; i < len; i++) {
if(!indices.contains(i)) {
output.add(original.get(i));
}
}
return output;
}
order your list of indexes, like this
if 2,12,9,7,3 order desc to 12,9,7,3,2
and then do this
for(var i = 0; i < indexes.length; i++)
{
source_array.remove(indexes[0]);
}
this should resolve your problem.
If the elements you wish to remove are all grouped together, you can do a subList(start, end).clear() operation.
If the elements you wish to remove are scattered, it may be better to create a new ArrayList, add only the elements you wish to include, and then copy back into the original list.
Edit: I realize now this was not a question of performance but of logic.
If you want to remove positions X to the Size
//a is the ArrayList
a=(ArrayList)a.sublist(0,X-1);
Assuming your indexes array is sorted (eg: 1, 3, 19, 29), you can do this:
for (int i = 0; i < indexes.size(); i++){
originalArray.remove(indexes.get(i) - i);
}
A more efficient method that I guess I have not seen above is creating a new Arraylist and selecting which indices survive by copying them to the new array. And finally reassign the reference.
I ended up here for a similar query and #aioobe's answer helped me figure out the solution.
However, if you are populating the list of indices to delete yourself, might want to consider using this:
indices.add(0, i);
This will eliminate the need for (the costly) reverse-sorting of the list before iterating over it, while removing elements from the main ArrayList.

Categories