Find the original index of sorted array - java

Suppose I have an array of String like this
String [] item={"B","C","D","A"};
that means
item[0]=B
item[1]=C
item[2]=D
item[3]=A
Now I have sorted this array and gets like
item[0]=A
item[1]=B
item[2]=C
item[3]=D
I want to know the original index of element C(which is 1 here ) . How to find that using code? May be my question is not clear ,please ask me anything you did not understand .

You cannot unless you save some additinal data. You could e.g. put both index and value inside a class and sort by value, or you could define a array containing the indices and sort that array instead:
Integer[] indices = new Integer[item.length];
for (int i = 0; i < indices.length; i++) {
indices[i] = i;
}
Arrays.sort(indices, new Comparator<Integer>() {
public int compare(Integer i1, Integer i2) {
return item[i1].compareTo(item[i2]);
}
});
Sorted values:
item[indices[0]]
item[indices[1]]
item[indices[2]]
item[indices[3]]
Original indices
indices[0]
indices[1]
indices[2]
indices[3]

After you sorted your array. How can you trace your original position?
I come to mind just 3 options:
Save all the swaps you did during the sort process
Save an original copy of the vector
Use a structure where you save actual position and original position.

Recap: you have two arrays, unsortedArray and sortedArray. For each element of sortedArray, you want to retrieve the corresponding index in unsortedArray.
public int getCorrespondingIndex(String[] unsortedArray, String[] sortedArray, int index){
for(int i=0; i<unsortedArray.length; i++)
if(sortedArray[index].equals(unsortedAray[i])
return i;
return -1;
}
public static void main(String args[]){
int oldIndex;
String[] unsortedArray = {"B","C","D","A"};
String[] sortedArray= {"A", "B", "C", "D"};
for(i=0; i<sortedArray.length; i++){
oldIndex = getCorrespondingIndex(unsortedArray, sortedArray, i);
System.out.println("The element "+sortedArray[i]+" was in position "+oldIndex);
}

Before you sort the array use a map to store original indexes of your array elements as follows.
String[] item = { "B", "C", "D", "A" };
Map<String, Integer> map = new HashMap<String, Integer>();
for (int i = 0; i < item.length; i++) {
map.put(item[i], i);
}
when you need you call as follows
map.get("A"); // here return the original index of "A"

Related

How to efficiently sort a Multidimensional Arrray

I was given a task to sort multidimensional array into ascending order without using the pre-made functions in the Array class (such as .sort).
I've tried asking some of my friends for ideas... Many of them turns the array into a single-dimensional array, sort it the way you would sort a single-dimensional array and then turns it back into a multidimensional array.
I'm just curious to know if there'd be any other ways to do this without having to go through such trouble.
I've found a solution... Thanks all
public static void sortAscending(int array[][]) {
int temp = 0;
for(int i = 0; i < array.length; i++) {
for(int j = 0; j < array[i].length; j++) {
for(int k = 0; k < array.length; k++) {
for(int l = 0; l < array[k].length; l++) {
if(array[i][j] < array[k][l]) {
temp = array[i][j];
array[i][j] = array[k][l];
array[k][l] = temp;
}
}
}
}
}
}
here is a full exemple you can tri
import java.util.Arrays;
import java.util.Comparator;
public class PartNumberQuantityDetailer {
// initialize a two dimensional array
static Integer[][] itemIdAndQty = new Integer[5][2];
public static void main(String[] args) {
// initialize array values
itemIdAndQty[0][0] = 1234;
itemIdAndQty[0][1] = 46;
itemIdAndQty[1][0] = 5443;
itemIdAndQty[1][1] = 564;
itemIdAndQty[2][0] = 362;
itemIdAndQty[2][1] = 24;
itemIdAndQty[3][0] = 6742;
itemIdAndQty[3][1] = 825;
itemIdAndQty[4][0] = 347;
itemIdAndQty[4][1] = 549;
System.out.println("Before sorting");
// show the contents of array
displayArray();
// sort the array on item id(first column)
Arrays.sort(itemIdAndQty, new Comparator<Integer[]>() {
#Override
//arguments to this method represent the arrays to be sorted
public int compare(Integer[] o1, Integer[] o2) {
//get the item ids which are at index 0 of the array
Integer itemIdOne = o1[0];
Integer itemIdTwo = o2[0];
// sort on item id
return itemIdOne.compareTo(itemIdTwo);
}
});
// display array after sort
System.out.println("After sorting on item id in ascending order");
displayArray();
// sort array on quantity(second column)
Arrays.sort(itemIdAndQty, new Comparator<Integer[]>() {
#Override
public int compare(Integer[] o1, Integer[] o2) {
Integer quantityOne = o1[1];
Integer quantityTwo = o2[1];
// reverse sort on quantity
return quantityOne.compareTo(quantityTwo);
}
});
// display array after sort
System.out.println("After sorting on quantity in ascending order");
displayArray();
}
private static void displayArray() {
System.out.println("-------------------------------------");
System.out.println("Item id\t\tQuantity");
for (int i = 0; i < itemIdAndQty.length; i++) {
Integer[] itemRecord = itemIdAndQty[i];
System.out.println(itemRecord[0] + "\t\t" + itemRecord[1]);
}
System.out.println("-------------------------------------");
}
}]
sort multidimensional array into ascending order:
You can sort multi-d array row-wise or column -wise.
If you don't want to flatten the array that is convert it into 1-d then that mean you have to go through each row or column depending on your choice and apply quick-sort(better performance for small data set if pivot is chosen optimally) or merge-sort.
So you can do both in (considering avg. case) O(nlogn) and say there are n rown or n columns the time complexity will be O(n^2(logn)).
Now above the assumption is that you want to sort either row-wise or column-wise.
If you want to achieve the both(row and column) then it's better if you convert the array to 1-d and then apply sort and then convert it back. Otherwise following above approach the time complexity can go O(n^2(logn)) but in the other case it will be O((n+m)log(n+m)) where n amd m are no. of rows and columns in array plus the O(n+m) space complexity.
In my opinion having a bit of space complexity so that you can bring down the run-time is preferable.

What is wrong with my remove method for certain array integers?

I have to create a method that will remove at certain value from an array and create a new array without that certain value. For example, if my array is (0,2,3,5,3) and I want to remove 3, the new array should be (0,2,5). For some reason, it only works for the first two digits.
import java.util.Scanner;
public class removeDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//array of numbers
int array[] = new int[] {0,1,2,3,4,5};
//invokes method and prints result
//System.out.println(remove(3,array));
remove(3,array);
}
//method remove that removes selected number from array
public static int[] remove(int v, int[] in) {
//count variable counts how many non-target numbers
int count = 0;
//for loop that checks if value at certain index is not equal to "v", the target number for removal
for(int k = 0; k < in.length; k++) {
//checks if certain number at certain index of array is not equal to v, or in this case, 3
if(in[k] != v) {
//counter
count++;
}
}
//new array that will stores values except "v"
int copy[] = new int[count];
//prints the length
System.out.println("array length: " + copy.length);
//for loop that checks if number not 3
for(int a = 1; a < in.length;) {
// sets number at certain index of main array into new array
if(in[a] != 3){
copy[a] = in[a];
a++;
System.out.println(copy[0]);
System.out.println(copy[1]);
System.out.println(copy[2]);
System.out.println(copy[3]);
}
else if(in[a] == 3) {
copy[a] = in[a+1];
}
}
//returns new array
return copy;
}
}
As said before, I need the new array to exclude the targeted number for removal.
You need two index variables for making the copy: one runs through the input array (a, as in the original code), and the other tracks your position in the output array (b, new variable). They can not be calculated from each other (they are the same at the beginning, but b can be significantly less than a at the end)
int b = 0;
for(int a = 0; a < in.length; a++) {
if(in[a] != v) {
copy[b] = in[a];
b++;
}
}
Using Java8 and it's streams feature you could do something like :
public static void main(String[] args) {
int[] array = {3236,47,34,34,73,46,3,64,473,4,4,346,4,63,644,4,6,4};
int[] newArray = removeAllOccurencesOf(array, 4);
System.out.println(Arrays.toString(newArray));
}
public static int[] removeAllOccurencesOf(int[] array, int numberToRemove)
{
//stream integers from array, filter the ones that correspond to number to remove, get what's left to new array
int[] newArray = IntStream.of(array).filter(i->i!=numberToRemove).toArray();
return newArray;
}
You can achieve the same result with some code like this:
// Add to params all inputs to remove from array
List<Integer> params = new ArrayList<>();
// Use Integer class instead of int datatype
Integer array[] = new Integer[] {0,1,2,3,4,3};
// Convert array to List class
List<Integer> list = new ArrayList<>(Arrays.asList(array));
// Remove all matches
list.removeAll(params);

I have some some random generated arrays: how can I print just the unique ones?

I have this code which randomly generates arrays of different lenghts (but with specific items according to my needs).
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class MarketBasketGeneratorAnon {
public static void main(String[] args) {
String[] elements = new String[]{"1", "2", "3", "4", "5", "6", "7","8"};
for (int i = 0; i < 99; i++) {
final String[] array = generateRandomArrayFromElements(elements);
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
}
private static String[] generateRandomArrayFromElements(String[] elements) {
int size = ThreadLocalRandom.current().nextInt(1, elements.length) + 1;
String[] array = new String[size];
ArrayList<Integer> usedIndices = new ArrayList<>(size);
for (int i = 0; i < array.length; i++) {
int randomIndex = getUniqueRandomIndex(usedIndices, size);
usedIndices.add(randomIndex);
array[i] = elements[randomIndex];
}
return array;
}
private static int getUniqueRandomIndex(ArrayList<Integer> usedIndices, int max) {
int randomIndex = ThreadLocalRandom.current().nextInt(0, max);
final boolean contains = usedIndices.contains(randomIndex);
if (contains)
randomIndex = getUniqueRandomIndex(usedIndices, max);
return randomIndex;
}
}
In this case, as you can see, I'm generating 100 arrays.
Then, I sort the elements in each array.
After sorting, of course many of these arrays become identical, having same lenght and same items in order.
I would like to print just one from each group of identical arrays, so that I get only unique arrays (no array is duplicated).
How can I edit my code to achieve that?
Thanks!
You can add your arrays to a Set: these are containers which don't permit duplicates.
Actually, you can't add arrays directly, because arrays don't implement the necessary methods such that two arrays with the same contents are considered equal (equals and hashCode); but you can wrap them in a data structure which does.
Set<List<String>> seenAlready = new HashSet<>();
// ...
for (int i = 0; i < 99; i++) {
final String[] array = generateRandomArrayFromElements(elements);
Arrays.sort(array);
if (seenAlready.add(Arrays.asList(array)) {
System.out.println(Arrays.toString(array));
}
}
Set.add returns true if the parameter is not already in the set. As such, this will print the array only if it wasn't already in the seenAlready set; and it adds the list representation of the array to the set so it won't be printed again.

How to sort multidimensional string array by one column in integer value in java?

I have for example this multidimensional array:
String[][] array = new String[10][2];
In the first column I have strings which are in my case usernames, but in the second column I have strings which should represent integers. Now I want to sort the array like this:
Before:
Petter 543
John 276
Jay 1879
Alf 5021
etc.
After:
Alf 5021
Jay 1879
Petter 543
John 276
etc.
So I want the highest value at the top and the lowest at the bottom but don't mess up the names. All I found till now is how to sort bother all integer multidimensional arrays or only string multidimensional arrays and not how to just sort the second column based on just integers.
I once got it sorted but it was sorted in "alphabetic" way:
So 1000 was the highest score
12 was the second highest score and
999999 was the lowest score.
Like 1 represents "a" and 9 represents "z".
Using Java 8 streams:
String[][] out = Arrays.stream(names)
.sorted(Comparator.comparing(x -> -Integer.parseInt(x[1])))
.toArray(String[][]::new);
If the person and the id are associated in some way, then it would be better to create a class that models them (POJO), make that POJO class comparable, define a list of the POJO and use Collections#sort to sorted according to the desired criteria...
another thing to consider is that you have a 2 dimentional String array
String[][] but your question states
...How to sort multidimensional string array by one column in integer value in java?
which means that you need to consider to parse the string to integer... (just as a nice hint)
public class MyPojo implement Comparator<MyPojo>{
private String name;
private String id;
...implements the method of the comparator
}
the do in the main test class
List<MyPojo> mList = new ArrayList<MyPojo>();
mList.add(...);
mList.add(...);
mList.add(...);
Collections.sort(mList);
System.out.println(mList)
Loop over the array until its sorted and swap each time it's not.
public static void main(String[] args) {
String[][] array = new String[4][2];
array[0][0] = "Petter"; array[0][1] = "543";
array[1][0] = "John"; array[1][1] = "276";
array[2][0] = "Jay"; array[2][1] = "1879";
array[3][0] = "Alf"; array[3][1] = "5021";
System.out.println(Arrays.deepToString(array)); // [[Petter, 543], [John, 276], [Jay, 1879], [Alf, 5021]]
sortArrayByScore(array);
System.out.println(Arrays.deepToString(array)); // [[Alf, 5021], [Jay, 1879], [Petter, 543], [John, 276]]
}
public static void sortArrayByScore(String[][] array) {
String tmpName, tmpScore;
boolean sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0 ; i < array.length - 1 ; i++) {
if (Integer.parseInt(array[i][1]) < Integer.parseInt(array[i+1][1])){
sorted = false;
// SWAP NAMES
tmpName = array[i][0];
array[i][0] = array[i+1][0];
array[i+1][0] = tmpName;
// SWAP SCORES
tmpScore = array[i][1];
array[i][1] = array[i+1][1];
array[i+1][1] = tmpScore;
}
}
}
}
My advice would be to take the second column of the 2D array, and put it in its own integer array. Then, call Arrays.sort() on that array. Finally, place the newly sorted array back into the 2D array as string values. Here is what it should look like,
int arr = new int[10];
String[][] copy = new String[10][2];
for(int i = 0; i < array.length; i++){
arr[i] = Integer.parseInt(array[i][1]);
System.arraycopy(array[i], 0, copy[i], 0, array[i].length);
}
Arrays.sort(arr);
for(int i = 0; i < array.length; i++){
array[i][1] = String.valueOf(arr[i]);
}
//fixing the names
for(int i = 0; i < copy.length; i++){
for(int j = 0; j < array.length; j++){
if(copy[i][1] == array[j][1]){
array[j][0] = copy[i][0];
break;
}
}
}
EDIT: To address the order of the names, I changed the code to include a copy of the 2D array so that after rewriting the integer values in order, a check is done to see where each integer moved. For each integer, the corresponding name is transferred to where the integer moved.
Use a comparator to sort the items in an array. In your case you have an array of arrays so you need a comparator for an array. You can use a Comparator of String array which assumes the 2nd item is the value.
public class SomeComparator implements Comparator<String[]> {
/**
* Assumes each row is length 2 and the 2nd String is really a number.
*/
#Override
public int compare(String[] row1, String[] row2) {
int value1 = Integer.parseInt(row1[1]);
int value2 = Integer.parseInt(row2[1]);
// compare value2 first to sort descending (high to low)
return Integer.compare(value2, value1);
}
}
Then you can sort using Arrays.sort like this
String[][] data = newData(); // or however you get your data
Arrays.sort(data, new SomeComparator());
You can use a Comparator that sorts the inner String[] items on the Integer value of the second element, instead of using the default string sort:
Arrays.sort(array, (o1, o2) -> Integer.valueOf(o2[1]).compareTo(Integer.valueOf(o1[1])));
Here you are using lambda syntax to do the same as would be achieved by:
Arrays.sort(data, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
return Integer.valueOf(o2[1]).compareTo(Integer.valueOf(o1[1]));
}
});

Convert a range of lists to sub list and store them in an list of type linkedlist

I already have a list type Integer with values in it and I want to test sequentially from index zero if the sum of one range of elements satisfy a particular value then copy this range in an list and store it in a list of linkedlist. Then again test sequentially but now from the following index of the previous range, so if the previous range was index 0 to index 9 then start at index 10, and repeat the process until the last index.
List<Integer> arrayB = new LinkedList<Integer>(); //this is the array with values in it
List<LinkedList> p = new LinkedList<LinkedList>();// this is the array of arrays
List<Integer> arrayA = new LinkedList<Integer>();// this is the range or the sub list of arrayB
public void function(int n)// suppose that n = 6 and arrayB have these value {1,2,3,1,1,1,1,2}
{
int count = 0;
for (int w : arrayB)
{
count = w + count;
arrayA.add(w);
if(count == n)
{
count = 0;
p.add((LinkedList) arrayA);
arrayA.clear();
}
}
}
However, this code fail when I call method clear in arrayA so is there any alternative to code with this logic regardless of the data structure used?
My understanding of the problem is the following:
There exists an array from which you would like to extract a certain range of values given that they satisfy some criteria. In this case, the criterion is that the range evaluates to some sum. Once this has been completed, you would like to repeat the process until all of the values in the original data-structure have been exhausted.
I will assume that your original data-structure is an array of integers, and that your resulting data-structure is a linkedlist of integer arrays.
One way to do it may be to keep a global counter that keeps track of the current index of the original array, such as something like the following:
int[] originalArray = {//list of numbers separated by commas};
LinkedList<Integer[]> resultingList = new LinkedList<>();
int currentIndex = 0;
public static void function(int totalSum) {
int currentSum = 0;
int initialIndex = currentIndex;
while((currentSum != totalSum) && (currentIndex < (originalArray.length - 1))) {
if(currentSum + initialArray[currentIndex] <= totalSum) {
currentSum += initialArray[currentIndex];
currentIndex++;
}
else {
break;
}
}
if(currentSum = totalSum) {
int[] arrayToAdd = new int[currentIndex - initialIndex - 1];
for(int i = 0; i < currentIndex - initialIndex; i++) {
arrayToAdd[i] = originalArray[initialIndex + i];
}
resultingList.add(arrayToAdd);
}
}
You are using the same list reference arrayA every time you add a sub list into p, every list element in p is pointing to the same arrayA . So when you call arrayA.clear(); You clear all the list elements in p.
To correct that, you need to create a new list object when you add a sublist to arrayA:
public static void function(int n)// suppose that n = 6 and arrayB have these value {1,2,3,1,1,1,1,2}
{
int count = 0;
LinkedList<Integer> subList = new LinkedList<>();
for (int w : arrayB) {
count = w + count;
subList.add(w);
if (count == n) {
count = 0;
p.add((LinkedList) subList); // p is adding a new list reference every time
subList = new LinkedList<>(); // create a new list object, subList points to a new list object
}
}
}
The issue is that when you add your linked list into the final storage p, you are assuming the elements of the list are put in there. Only a pointer is referenced, so when you clear it the next line, all the elements are gone.
p.add((LinkedList) arrayA);
arrayA.clear();
One tip is to move arrayA's scope to inside the function. This is because it's temporary, and only a sublist, so it shouldn't be at the instance level. It can be reused by doing a
arrayA = new LinkedList<Integer>();
and when doing so, you haven't lost the old list because p is keeping a reference to it.
Another tip is to name your lists with meaningful names.
originalIntList, groupedIntList, singleGroupIntList help the reader figure out what they could be doing more than a comment stating obvious aspects of the Java object.

Categories