This question already has answers here:
Sort a parallel array using Arrays.sort()
(5 answers)
Closed 6 years ago.
Using Arrays.sort( array ); is a very easy way to sort an array. But there is a problem. For each unsorted array, there is an index which is referring to an object in some other data structure. When sorting an array (using the above code or any other similar ways) the index of each value will be changed. Is there a solution to have the assigned index of each value?
EDIT
Using HashMap<Key, Value> will not be useful since there are a lot of same values in the array.
Sort both data structures in parallel.
Or make the reference index (to reference the other data structure) an internal field of each element, so that each element maintains the same "reference index" even if the order of the elements is changed by sorting.
Or better yet, just give each element an internal field that is just a direct reference variable to the element in the other data structure. (unless you need the raw index itself for some reason and not just a reference to the associated object / value)
For example: this SO Q&A
First, having two parallel arrays with elements in corresponding indexes indicates you might want to change the data structure to a single array with a container object containing two fields. This container object would then implement Comparable interface.
But, sticking with what you say, one approach could be:
/**
* Sorts parallel arrays in-place. Sorted by the first array and updating
* all other arrays to match.
* Uses the natural sorting of the objects.
* All arrays must be the same length.
*
* #param keys the values used to sort, may be duplicate
*
* #param otherArrays the arrays to have reordered to match the sorting of
* the keys array.
*
* #exception IllegalArgumentException if any of otherArrays have a length
* different that the keys array.
*/
public static <E extends Comparable<? super E>> void sortParallelArrays(
E[] keys,
Object[] ... otherArrays
) {
int numKeys = keys.length;
int numOtherArrays = otherArrays.length;
for(Object[] otherArray : otherArrays) {
if(otherArray.length != numKeys) {
throw new IllegalArgumentException("Mismatched array lengths");
}
}
// A list of all indexes per key
// This also does the sorting within the TreeMap using natural ordering
SortedMap<E, List<Integer>> originalIndexesByKey = new TreeMap<E, List<Integer>>();
// Populate the map
for(int i = 0; i < numKeys; i++) {
E key = keys[i];
List<Integer> originalIndexes = originalIndexesByKey.get(key);
if(originalIndexes == null) {
// Optimization for the non-duplicate keys
originalIndexesByKey.put(key, Collections.singletonList(i));
} else {
if(originalIndexes.size() == 1) {
// Upgrade to ArrayList now that know have duplicate keys
originalIndexes = new ArrayList<Integer>(originalIndexes);
originalIndexesByKey.put(key, originalIndexes);
}
originalIndexes.add(i);
}
}
// Store back to keys and sort other arrays in a single traversal
Object[][] sortedOtherArrays = new Object[numOtherArrays][numKeys];
int pos = 0;
for(Map.Entry<E, List<Integer>> entry : originalIndexesByKey.entrySet()) {
E key = entry.getKey();
for(int index : entry.getValue()) {
keys[pos] = key;
for(int ooIndex = 0; ooIndex < numOtherArrays; ooIndex++) {
sortedOtherArrays[ooIndex][pos] = otherArrays[ooIndex][index];
}
pos++;
}
}
assert pos == numKeys : "Arrays should be full";
// Copy back to original arrays for in-place sort
for(int ooIndex = 0; ooIndex < numOtherArrays; ooIndex++) {
System.arraycopy(
sortedOtherArrays[ooIndex], 0,
otherArrays[ooIndex], 0,
numKeys);
}
}
This is not the most memory efficient strategy, but isn't much code.
The time complexity isn't too bad. Looks something like O((M+1)*N*log(N)), where M is the number of otherArrays and N is the number of keys. No crazy worst-case issues, at least.
Related
I have sorted List<Pair<Integer, Integer>> and I want to create a subList for all the Pairs which having a key less than one arbitrary value k.
I want to create a subList that follows above condition and sort it.
I did something like this -
//to get the max index of the List
public static int getIndex(List<Pair<Integer,Integer>> list,int key)
{
int count=0;
for(Pair<Integer,Integer> p: list)
{
if(p.getKey()>key)
break;
count++;
}
return count;
}
Now, Sorting subList as per this criteria
int count = getIndex(current.getValue(),list);
Collections.sort(list.subList(0, count),Comparator.<Pair<Integer,Integer>>comparingInt(Pair::getValue));
Is there any elegent way to do achieve this ? I mean java 8 way.
Stream API came into my mind. But after performing operations it doesn't manipulate the underlined collection.
Something like the following.
List<Pair<Integer,Integer>> subList =
list.stream()
.filter(p->p.getKey() < key)
.collect(Collectors.toList());
This works regardless of the ordering of the pairs in the list. It constructs the new list as each pair passes thru the filter.
Now this the question am trying to answer:
Write a method which takes a sparse array as an argument and returns
a new equivalent dense array.The dense array only needs to be large enough to fit all of the values.For example,the resulting dense array only needs to hold 90 values if the last element in the sparse array is at index 89.
dense array:[3,8,4,7,9,0,5,0] the number are generated randomly.
sparse array is an arraylist of arrays [[0,3],[1,8],[2,4],[3,7],[4,9],[6,5]]
so in the sparse array if the number generated is !0 the value and its index are stored in array of size 2 but if the number generated is 0 nothing is stored
When you have a fixed size for element (as array) in your collection. Your solution is OK and that is a fast way.
But when your element does not have a fixed size, such as: [[1,2,3],[4,5],[6],[7,8,9,10,11]] so you can interator through your element:
for(int[] e : sparseArr)
{
for(int number : e)
{
tree.add(number);
}
}
No matter how many element in your sparseArr, no how long of your element>
To sort your element, I recommend you should use TreeSet<E>, element push into tree will be sorted automatically.
So if you just want to store 2 Integers paired together I recommend going with HashMaps. In your case you would use:
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
HashMaps support .containsKey(key); as well as .containsValue(value);
If you want to check all entries you can transform the Map to an entrySet:
for(Entry<Integer, Integer> e : map.entrySet()) {
int one = e.getKey();
int two = e.getValue();
}
Unless you want to do something more special than just storing 2 paired Integers I really can recommend doing it this way!
The method you're after should do something like this
public int[] sparseToDense (ArrayList<int[]> sparse) {
int i = 0;
int[] dense = new int[sparse.get(sparse.size()-1)[0]];
int[] sp;
ListIterator<int[]> iter = sparse.listIterator();
while (iter.hasNext()) {
sp = iter.next();
while (sp[0] != i) {
dense[i++] = 0;
}
dense[i++] = sp[1];
}
return dense;
}
Just another way to do that, since you have java 8, you will be able to use stream. But if you're a beginner, i recommend you to try with for loops and arrays, will be better for your learning.
public static ArrayList<Integer> returnDense(ArrayList<int[]> sparse) {
return sparse.stream().flatMap(p -> IntStream.of(p).boxed())
.collect(Collectors.toCollection(ArrayList::new));
}
also if you decide change int[] to Integer[].
public ArrayList<Integer> returnDense(ArrayList<Integer[]> sparse) {
return sparse.stream().flatMap(p -> Arrays.asList(p).stream()).filter(Objects::nonNull)
.collect(Collectors.toCollection(ArrayList::new));
}
.filter(Objects::nonNull) is to be sure that will not have nulls values, but if you know that will not have it, that isn't necessary.
I'm having trouble implementing an add method to an array structure for my data structures class and am not able to find a way to wrap my head around how to do this correctly. I am aware this is an impractical way handling data, but hey data structures.
Instructions:
The add method ensures that this set contains the specified element.
Neither duplicates nor null values are allowed. The method returns
true if this set was modified (i.e., the element was added) and false
otherwise. If the array is full, you must “resize” to an array twice
as large. Note that the constraint on the generic type parameter T of
the ArraySet class ensures that there is a natural order on the values
stored in an ArraySet. You must maintain the internal array in
ascending natural order at all times. The time complexity of the add
method must be O ( N ), where N is the number of elements in the set.
We are able to use the Array and Iterator classes only! Please do not give an answer using arraylists.
My Psudocode is:
Check element exists, check if array is full, if full double size,
compare elements to find an index where we can maintain natural order
and insert element or find the duplicate and exit, copy array from
top down and combine with inserted element and bottom part.
Actual Code:
//Given Fields
T[] elements;
int size;
//Add Method
public boolean add(T element) {
if (element != null) {
int index = -1;
int last_compare = -1;
for (int i = 0; i < size; i++) {
int compare = elements[i].compareTo(element);
if (compare > 0 && last_compare < 0) { //larger element, last element was smaller.
if (isFull()) {
resize(elements.length * 2);
}
index = i;
break;
} else if (compare == 0) {
return false;
}
last_compare = compare;
}
T[] temp = null;
//Need to copy the array here
} else {
return false;
}
}
I don't know how to insert this correctly while maintaining O(N) time complexity.
Any ideas?
There are two sub-problems.
1- Comparing two huge arraylists
2- Sorting elements of arraylist based on the values of its object to achieve (1).
I have an ArrayList of objects of a class. i.e.
Class X
{
double x;
double y;
int sortVal;
}
ArrayList<X> alX = new ArrayList<X>(); //size = 10,000
ArrayList<Integer> myValue = new ArrayList<Integer>(); //size = 15
I want to check if myValue is present in sortVal.
X ob = new X();
for(i=0;i<myValue.size();i++)
{
for(j=0;j<alX.size();j++)
{
ob = alX.get(j)
**if (myValues.get(i) == ob.sortVal)**
}
}
As the size of the arraylist 'alX' is huge, it takes high computation time.
I thought the better way would be to sort the elemets of ArrayList alX based on the values of sortVal of Class X. By sorting, once sortVal is greater than myValue, I can break from the loop.
1) how can I sort the elements of arraylist alX based on the value 'sortVal'.
2) Is there a better approach, than sorting the arraylist, to compare the two values. i.e. (myValues.get(i) == alX.ob.sortVal)
[edit] Consider the values being,
ArrayList<X>:
x : 1,1,1,2,3,5,4,5
y : 2,4,6,4,4,6,2,1
sortVal: 10,20,30,10,10,20,30
ArrayList<Integer>:
myValue: 10,20,30
You could construct a Map<Integer, X> if sortVal values are unique or Map<Integer, Lists<X>> if they are not. This has a time complexity of O(n) instead or O(n * log n) which is the cost of doing a sort.
EDIT: This builds a MultiMap of keys and the set of objects for that key in one pass.
List<X> xs = ...
Map<Integer, Set<X>> mapBySortVal = new LinkedHashMap<>();
for(X x: xs) {
Set<X> set = mapBySortVal.get(x.sortVal);
if (set == null)
mapBySortVal.put(x.sortVal, set = new LinkedHashSet<>());
set.add(x);
}
for(Integer value: myValues) {
Set<X> xs = mapBySortVal.get(value);
if (xs != null)
// found some.
}
For your first question, you can sort a collection on anything you can think of by specifying the Comparator it should use (see Collections#sort)
Since you named your field sortVal, I would guess instances of this class can be sorted based on that value and you might want to implement the Comparable interface for that class. That way, you can use Collections#sort without having to specify the Comparator
Google guava get very useful functions. For ordering of arrays it provide com.google.common.collect.Ordering<T>.
For example:
Ordering<String> byLengthOrdering = new Ordering<String>() {
public int compare(String left, String right) {
return Ints.compare(left.length(), right.length());
}
};
List<String> sorted = byLengthOrdering.reverse().sortedCopy(sourceList);
Depending on your requirement there are 2 approaches:
Use Map, which orders its elements by natural order by default. But will take more memory.
OR
Sort using comparator. Will take more time.
Just look at their docs for explanation.
In PHP, you can dynamically add elements to arrays by the following:
$x = new Array();
$x[] = 1;
$x[] = 2;
After this, $x would be an array like this: {1,2}.
Is there a way to do something similar in Java?
Look at java.util.LinkedList or java.util.ArrayList
List<Integer> x = new ArrayList<Integer>();
x.add(1);
x.add(2);
Arrays in Java have a fixed size, so you can't "add something at the end" as you could do in PHP.
A bit similar to the PHP behaviour is this:
int[] addElement(int[] org, int added) {
int[] result = Arrays.copyOf(org, org.length +1);
result[org.length] = added;
return result;
}
Then you can write:
x = new int[0];
x = addElement(x, 1);
x = addElement(x, 2);
System.out.println(Arrays.toString(x));
But this scheme is horribly inefficient for larger arrays, as it makes a copy of the whole array each time. (And it is in fact not completely equivalent to PHP, since your old arrays stays the same).
The PHP arrays are in fact quite the same as a Java HashMap with an added "max key", so it would know which key to use next, and a strange iteration order (and a strange equivalence relation between Integer keys and some Strings). But for simple indexed collections, better use a List in Java, like the other answerers proposed.
If you want to avoid using List because of the overhead of wrapping every int in an Integer, consider using reimplementations of collections for primitive types, which use arrays internally, but will not do a copy on every change, only when the internal array is full (just like ArrayList). (One quickly googled example is this IntList class.)
Guava contains methods creating such wrappers in Ints.asList, Longs.asList, etc.
Apache Commons has an ArrayUtils implementation to add an element at the end of the new array:
/** Copies the given array and adds the given element at the end of the new array. */
public static <T> T[] add(T[] array, T element)
I have seen this question very often in the web and in my opinion, many people with high reputation did not answer these questions properly. So I would like to express my own answer here.
First we should consider there is a difference between array and arraylist.
The question asks for adding an element to an array, and not ArrayList
The answer is quite simple. It can be done in 3 steps.
Convert array to an arraylist
Add element to the arrayList
Convert back the new arrayList to the array
Here is the simple picture of it
And finally here is the code:
Step 1:
public List<String> convertArrayToList(String[] array){
List<String> stringList = new ArrayList<String>(Arrays.asList(array));
return stringList;
}
Step 2:
public List<String> addToList(String element,List<String> list){
list.add(element);
return list;
}
Step 3:
public String[] convertListToArray(List<String> list){
String[] ins = (String[])list.toArray(new String[list.size()]);
return ins;
}
Step 4
public String[] addNewItemToArray(String element,String [] array){
List<String> list = convertArrayToList(array);
list= addToList(element,list);
return convertListToArray(list);
}
You can use an ArrayList and then use the toArray() method. But depending on what you are doing, you might not even need an array at all. Look into seeing if Lists are more what you want.
See: Java List Tutorial
You probably want to use an ArrayList for this -- for a dynamically sized array like structure.
You can dynamically add elements to an array using Collection Frameworks in JAVA. collection Framework doesn't work on primitive data types.
This Collection framework will be available in "java.util.*" package
For example if you use ArrayList,
Create an object to it and then add number of elements (any type like String, Integer ...etc)
ArrayList a = new ArrayList();
a.add("suman");
a.add(new Integer(3));
a.add("gurram");
Now you were added 3 elements to an array.
if you want to remove any of added elements
a.remove("suman");
again if you want to add any element
a.add("Gurram");
So the array size is incresing / decreasing dynamically..
Use an ArrayList or juggle to arrays to auto increment the array size.
keep a count of where you are in the primitive array
class recordStuff extends Thread
{
double[] aListOfDoubles;
int i = 0;
void run()
{
double newData;
newData = getNewData(); // gets data from somewhere
aListofDoubles[i] = newData; // adds it to the primitive array of doubles
i++ // increments the counter for the next pass
System.out.println("mode: " + doStuff());
}
void doStuff()
{
// Calculate the mode of the double[] array
for (int i = 0; i < aListOfDoubles.length; i++)
{
int count = 0;
for (int j = 0; j < aListOfDoubles.length; j++)
{
if (a[j] == a[i]) count++;
}
if (count > maxCount)
{
maxCount = count;
maxValue = aListOfDoubles[i];
}
}
return maxValue;
}
}
This is a simple way to add to an array in java. I used a second array to store my original array, and then added one more element to it. After that I passed that array back to the original one.
int [] test = {12,22,33};
int [] test2= new int[test.length+1];
int m=5;int mz=0;
for ( int test3: test)
{
test2[mz]=test3; mz++;
}
test2[mz++]=m;
test=test2;
for ( int test3: test)
{
System.out.println(test3);
}
In Java size of array is fixed , but you can add elements dynamically to a fixed sized array using its index and for loop. Please find example below.
package simplejava;
import java.util.Arrays;
/**
*
* #author sashant
*/
public class SimpleJava {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
try{
String[] transactions;
transactions = new String[10];
for(int i = 0; i < transactions.length; i++){
transactions[i] = "transaction - "+Integer.toString(i);
}
System.out.println(Arrays.toString(transactions));
}catch(Exception exc){
System.out.println(exc.getMessage());
System.out.println(Arrays.toString(exc.getStackTrace()));
}
}
}