I have the following 3 arrays:
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
I want to sort the three arrays based on the indexes:
indexes -> {0,2,5,8}
sources -> {"how", "are", "you", "today"}
targets -> {"I", "am", "fine", "thanks"}
I can create a new class myClass with all three elements:
class myClass {
int x;
String source;
String target;
}
Reassign everything to myClass, then sort myClass using x. However, this would required additional spaces. I am wondering if it is possible to do in place sorting? Thanks!
Three ways of doing this
1. Using Comparator (Need Java 8 plus)
import java.io.*;
import java.util.*;
class Test {
public static String[] sortWithIndex (String[] strArr, int[] intIndex )
{
if (! isSorted(intIndex)){
final List<String> stringList = Arrays.asList(strArr);
Collections.sort(stringList, Comparator.comparing(s -> intIndex[stringList.indexOf(s)]));
return stringList.toArray(new String[stringList.size()]);
}
else
return strArr;
}
public static boolean isSorted(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] < arr[i]) {
return false;
};
}
return true;
}
// Driver program to test function.
public static void main(String args[])
{
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
String[] sortedSources = sortWithIndex(sources,indexes);
String[] sortedTargets = sortWithIndex(targets,indexes);
Arrays.sort(indexes);
System.out.println("Sorted Sources " + Arrays.toString(sortedSources) + " Sorted Targets " + Arrays.toString(sortedTargets) + " Sorted Indexes " + Arrays.toString(indexes));
}
}
Output
Sorted Sources [how, are, you, today] Sorted Targets [I, am, fine, thanks] Sorted Indexes [0, 2, 5, 8]
2. Using Lambda (Need Java 8 plus)
import java.io.*;
import java.util.*;
public class Test {
public static String[] sortWithIndex (String[] strArr, int[] intIndex )
{
if (! isSorted(intIndex)) {
final List<String> stringList = Arrays.asList(strArr);
Collections.sort(stringList, (left, right) -> intIndex[stringList.indexOf(left)] - intIndex[stringList.indexOf(right)]);
return stringList.toArray(new String[stringList.size()]);
}
else
return strArr;
}
public static boolean isSorted(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] < arr[i]) {
return false;
};
}
return true;
}
// Driver program to test function.
public static void main(String args[])
{
int[] indexes = new int[]{0,2,5,8};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
String[] sortedSources = sortWithIndex(sources,indexes);
String[] sortedTargets = sortWithIndex(targets,indexes);
Arrays.sort(indexes);
System.out.println("Sorted Sources " + Arrays.toString(sortedSources) + " Sorted Targets " + Arrays.toString(sortedTargets) + " Sorted Indexes " + Arrays.toString(indexes));
}
}
3. Using Lists and Maps and avoiding multiple calls (as in second solution above) to the method to sort individual arrays
import java.util.*;
import java.lang.*;
import java.io.*;
public class Test{
public static <T extends Comparable<T>> void sortWithIndex( final List<T> key, List<?>... lists){
// input validation
if(key == null || lists == null)
throw new NullPointerException("Key cannot be null.");
for(List<?> list : lists)
if(list.size() != key.size())
throw new IllegalArgumentException("All lists should be of the same size");
// Lists are size 0 or 1, nothing to sort
if(key.size() < 2)
return;
// Create a List of indices
List<Integer> indices = new ArrayList<Integer>();
for(int i = 0; i < key.size(); i++)
indices.add(i);
// Sort the indices list based on the key
Collections.sort(indices, new Comparator<Integer>(){
#Override public int compare(Integer i, Integer j) {
return key.get(i).compareTo(key.get(j));
}
});
Map<Integer, Integer> swapMap = new HashMap<Integer, Integer>(indices.size());
List<Integer> swapFrom = new ArrayList<Integer>(indices.size()),
swapTo = new ArrayList<Integer>(indices.size());
// create a mapping that allows sorting of the List by N swaps.
for(int i = 0; i < key.size(); i++){
int k = indices.get(i);
while(i != k && swapMap.containsKey(k))
k = swapMap.get(k);
swapFrom.add(i);
swapTo.add(k);
swapMap.put(i, k);
}
// use the swap order to sort each list by swapping elements
for(List<?> list : lists)
for(int i = 0; i < list.size(); i++)
Collections.swap(list, swapFrom.get(i), swapTo.get(i));
}
public static void main (String[] args) throws java.lang.Exception{
List<Integer> index = Arrays.asList(0,2,8,5);
List<String> sources = Arrays.asList("how", "are", "today", "you");
// List Types do not need to be the same
List<String> targets = Arrays.asList("I", "am", "thanks", "fine");
sortWithIndex(index, index, sources, targets);
System.out.println("Sorted Sources " + sources + " Sorted Targets " + targets + " Sorted Indexes " + index);
}
}
Output
Sorted Sources [how, are, you, today] Sorted Targets [I, am, fine, thanks] Sorted Indexes [0, 2, 5, 8]
It is possible although it is not that easy than it looks like. There are two options:
write your own sort algorithm where the swap function for two elements also swaps the elements in the other arrays.
AFAIK there is no way to extend the standard Array.sort in a way that it swaps additional arrays.
Use a helper array with the sort order.
First of all you need to initialize the helper array with the range {0, 1 ... indexes.Length-1}.
Now you sort the helper array using a Comparator that compares indexes[a] with indexes[b] rather than a to b.
The result is an helper array where each element has the index of the element of the source array where its content should come from, i.e. the sort sequence.
The last step is the most tricky one. You need to swap the elements in your source arrays according to the sort sequence above.
To operate strictly in place set your current index cur to 0.
Then take the cur-th element from your helper array. Let's call it from. This is the element index that should be placed at index cur after completion.
Now you need to make space at index cur to place the elements from index from there. Copy them to a temporary location tmp.
Now move the elements from index from to index cur. Index from is now free to be overridden.
Set the element in the helper array at index cur to some invalid value, e.g. -1.
Set your current index cur to from proceed from above until you reach an element in the helper array which already has an invalid index value, i.e. your starting point. In this case store the content of tmp at the last index. You now have found a closed loop of rotated indices.
Unfortunately there may exist an arbitrary number of such loops each of arbitrary size. So you need to seek in the helper array for the next non-invalid index value and again continue from above until all elements of the helper array are processed.
Since you will end at the starting point after each loop it is sufficient to increment cur unless you find an non-invalid entry. So the algorithm is still O(n) while processing the helper array.
All entries before cur are necessarily invalid after a loop completed.
If curincrements beyond the size of the helper array you are done.
There is an easier variation of option 2 when you are allowed to create new target arrays.
In this case you simply allocate the new target arrays and fill their content according to the indices in your helper array.
The drawback is that the allocations might be quite expensive if the arrays are really large. And of course, it is no longer in place.
Some further notes.
Normally the custom sort algorithm performs better as it avoids the allocation of the temporary array. But in some cases the situation changes. The processing of the cyclic element rotation loops uses a minimum move operations. This is O(n) rather than O(n log n) of common sort algorithms.
So when the number of arrays to sort and or the size of the arrays grows the method #2 has an advantage because it uses less swap operations.
A data model requiring a sort algorithm like this is mostly broken by design. Of course, like always there are a few cases where you can't avoid this.
May I suggest you to use a TreeMap or something similar, using your integer as key.
static Map<Integer, myClass> map = new TreeMap<>();
So when you want to retrieve ordered you only have to do a for loop or whatever you prefer.
for (int i : map.keyset()){
System.out.println("x: "+map.get(i).x+"\nsource: "+map.get(i).source+"\ntarget: "+map.get(i).target);
}
This example requires creating an Integer array of indexes, but the arrays to be sorted are reordered in place according to array1, and the arrays can be of any type (primitives or objects) that allows indexing.
public static void main(String[] args) {
int array1[]={5,1,9,3,8};
int array2[]={2,0,3,6,1};
int array3[]={3,1,4,5,9};
// generate array of indices
Integer[] I = new Integer [array1.length];
for(int i = 0; i < I.length; i++)
I[i] = i;
// sort array of indices according to array1
Arrays.sort(I, (i, j) -> array1[i]-array1[j]);
// reorder array1 ... array3 in place using sorted indices
// also reorder indices back to 0 to length-1
// time complexity is O(n)
for(int i = 0; i < I.length; i++){
if(i != I[i]){
int t1 = array1[i];
int t2 = array2[i];
int t3 = array3[i];
int j;
int k = i;
while(i != (j = I[k])){
array1[k] = array1[j];
array2[k] = array2[j];
array3[k] = array3[j];
I[k] = k;
k = j;
}
array1[k] = t1;
array2[k] = t2;
array3[k] = t3;
I[k] = k;
}
}
// display result
for (int i = 0; i < array1.length; i++) {
System.out.println("array1 " + array1[i] +
" array2 " + array2[i] +
" array3 " + array3[i]);
}
}
Another solution using Collection (increase the memory usage) :
Let's create a sorted map to will simply be a mapping between the correct index and the original position :
public static TreeMap<Integer, Integer> sortIndex(int[] array){
TreeMap<Integer, Integer> tree = new TreeMap<>();
for(int i=0; i < array.length; ++i) {
tree.put(array[i], i);
}
return tree;
}
Test :
int[] indexes = new int[] { 0, 1, 3, 2, 4, 5 };
TreeMap<Integer, Integer> map = sortIndex(indexes);
map.keySet().stream().forEach(System.out::print); //012345
map.values().stream().forEach(System.out::print); //013245
We have the indexes sorted (on the key) and the original index order as the values.
No we can simple use this to order the array, I will be drastic and use a Stream to map and collect into a List.
public static List<String> sortInPlace(String[] array, TreeMap<Integer, Integer> map) {
return map.values().stream().map(i -> array[i]).collect(Collectors.toList());
}
Test :
String[] sources = "to be not or to be".split(" ");
int[] indexes = new int[] { 0, 1, 3, 2, 4, 5 };
TreeMap<Integer, Integer> map = sortIndex(indexes);
List<String> result = sortInPlace(sources, map);
System.out.println(result);
[to, be, or, not, to, be]
Why did I use a List. Mostly to simplify the re-ordering, if we try to order the original arrays, it will be complicated because we need to remove the opposed key/pair
2 -> 3
3 -> 2
Without some cleaning, we will just swap the cells twice ... so there will be no changes.
If we want to reduce a bit the memory usage, we can create another array instead of using the stream and copy values per values iterating the map. This would be possible to do with multiple array in parallel too.
It all depends on the size of your arrays. This solution will use the first array to perform the sorting but will perform the permutation on multiple arrays.
So this could have some performances issues if the sorting algorithm used will need a lot of permutation.
Here, I took a basic sorting algorithm on which I have added some actions I can do during the swap of two cells. This allows use to define some lambda to swap multiple array at the same time based on one array.
public static void sortArray( int[] array, BiConsumer<Integer, Integer>... actions ) {
int tmp;
for ( int i = 0, length = array.length; i < length; ++i ) {
tmp = array[i];
for ( int j = i + 1; j < length; ++j ) {
if ( tmp > array[j] ) {
array[i] = array[j];
array[j] = tmp;
tmp = array[i];
// Swap the other arrays
for ( BiConsumer<Integer, Integer> cons : actions ){
cons.accept( i, j);
}
}
}
}
}
Let's create a generic method to swap the cells that we can pass as a BiConsumer lambda (only works for non-primitive arrays):
public static <T> void swapCell( T[] array, int from, int to ) {
T tmp = array[from];
array[from] = array[to];
array[to] = tmp;
}
That allows use to sort the arrays like :
public static void main( String[] args ) throws ParseException {
int[] indexes = new int[] { 0, 2, 8, 5 };
String[] sources = new String[] { "how", "are", "today", "you" };
String[] targets = new String[] { "I", "am", "thanks", "fine" };
sortArray( indexes,
( i, j ) -> swapCell( sources, i, j ),
( i, j ) -> swapCell( targets, i, j ) );
System.out.println( Arrays.toString( indexes ) );
System.out.println( Arrays.toString( sources ) );
System.out.println( Arrays.toString( targets ) );
}
[0, 2, 5, 8]
[how, are, you, today]
[I, am, fine, thanks]
This solution does not required (much) more memory than the one already used since no additional array or Collection are required.
The use of BiConsumer<>... provide a generic solution, this could also accept an Object[]... but this would not work for primitives array anymore. This have a slight performance lost of course, so based on the need, this can be removed.
Creation of a complete solution, first let's define an interface that will be used as a factory as well :
interface Sorter {
void sort(int[] array, BiConsumer<Integer, Integer>... actions);
static void sortArrays(int[] array, BiConsumer<Integer, Integer>... actions){
// call the implemented Sorter
}
}
Then, implement a simple Selection sorterr with the same logic as before, for each permutation in the original array, we execute the BiConsumer:
class SelectionSorter implements Sorter {
public void sort(int[] array, BiConsumer<Integer, Integer>... actions) {
int index;
int value;
int tmp;
for (int i = 0, length = array.length; i < length; ++i) {
index = i;
value = array[i];
for (int j = i + 1; j < length; ++j) {
if (value > array[j]) {
index = j;
value = array[j];
}
}
if (index != i) {
tmp = array[i];
array[i] = array[index];
array[index] = tmp;
// Swap the other arrays
for (BiConsumer<Integer, Integer> cons : actions) {
cons.accept(i, index);
}
}
}
}
}
Let also create a Bubble sorter :
class BubbleSorter implements Sorter {
public void sort(int[] array, BiConsumer<Integer, Integer>... actions) {
int tmp;
boolean swapped;
do {
swapped = false;
for (int i = 1, length = array.length; i < length; ++i) {
if (array[i - 1] > array[i]) {
tmp = array[i];
array[i] = array[i - 1];
array[i - 1] = tmp;
// Swap the other arrays
for (BiConsumer<Integer, Integer> cons : actions) {
cons.accept(i, i - 1);
}
swapped = true;
}
}
} while (swapped);
}
}
Now, we can simple call one or the other based on a simple condition, the length :
static void sortArrays(int[] array, BiConsumer<Integer, Integer>... actions){
if(array.length < 1000){
new BubbleSorter().sort(array, actions);
} else {
new SelectionSorter().sort(array, actions);
}
}
That way, we can call our sorter simply with
Sorter.sortArrays(indexes,
(i, j) -> swapCell(sources, i, j),
(i, j) -> swapCell(targets, i, j)
);
Complete test case on ideone (limit on size because of the time out)
I wonder if my approach is valid.
public class rakesh{
public static void sort_myClass(myClass myClasses[]){
for(int i=0; i<myClasses.length; i++){
for(int j=0; j<myClasses.length-i-1; j++){
if(myClasses[j].x >myClasses[j+1].x){
myClass temp_myClass = new myClass(myClasses[j+1]);
myClasses[j+1] = new myClass(myClasses[j]);
myClasses[j] = new myClass(temp_myClass);
}
}
}
}
public static class myClass{
int x;
String source;
String target;
myClass(int x,String source,String target){
this.x = x;
this.source = source;
this.target = target;
}
myClass(myClass super_myClass){
this.x = super_myClass.x;
this.source = super_myClass.source;
this.target = super_myClass.target;
}
}
public static void main(String args[]) {
myClass myClass1 = new myClass(0,"how","I");
myClass myClass2 = new myClass(2,"are","am");
myClass myClass3 = new myClass(8,"today","thanks");
myClass myClass4 = new myClass(5,"you","fine");
myClass[] myClasses = {myClass1, myClass2, myClass3, myClass4};
sort_myClass(myClasses);
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.x + " ");
}
System.out.print("\n");
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.source + " ");
}
System.out.print("\n");
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.target + " ");
}
}
}
If you find any error or have suggestions then please leave a comment so I could make any necessary edits.
Output
0 2 5 8
how are you today
I am fine thanks
Process finished with exit code 0
without assign values in class, you can achieve it with following code:
Integer[] indexes = new Integer[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
Integer[] sortedArrya = Arrays.copyOf(indexes, indexes.length);
Arrays.sort(sortedArrya);
String[] sortedSourses = new String[sources.length];
String[] sortedTargets = new String[targets.length];
for (int i = 0; i < sortedArrya.length; i++) {
int intValus = sortedArrya[i];
int inx = Arrays.asList(indexes).indexOf(intValus);
sortedSourses[i] = sources[+inx];
sortedTargets[i] = targets[+inx];
}
System.out.println(sortedArrya);
System.out.println(sortedSourses);
System.out.println(sortedTargets);
I have an other solution for your question:
private void reOrder(int[] indexes, String[] sources, String[] targets){
int[] reIndexs = new int[indexes.length]; // contain index of item from MIN to MAX
String[] reSources = new String[indexes.length]; // array sources after re-order follow reIndexs
String[] reTargets = new String[indexes.length]; // array targets after re-order follow reIndexs
for (int i=0; i < (indexes.length - 1); i++){
if (i == (indexes.length - 2)){
if (indexes[i] > indexes[i+1]){
reIndexs[i] = i+1;
reIndexs[i+1] = i;
}else
{
reIndexs[i] = i;
reIndexs[i+1] = i+1;
}
}else
{
for (int j=(i+1); j < indexes.length; j++){
if (indexes[i] > indexes[j]){
reIndexs[i] = j;
}else {
reIndexs[i] = i;
}
}
}
}
// Re-order sources array and targets array
for (int index = 0; index < reIndexs.length; index++){
reSources[index] = sources[reIndexs[index]];
reTargets[index] = targets[reIndexs[index]];
}
// Print to view result
System.out.println( Arrays.toString(reIndexs));
System.out.println( Arrays.toString(reSources));
System.out.println( Arrays.toString(reTargets));
}
You can also achieve in your way too.
Here I created an ArrayList myArr and sorted Based on index value and then converted back to the array if you satisfied with ArrayList just you can remove the conversion or you want Array this one be helpful.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
public class StackOverflow {
public static void main(String[] args) {
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
ArrayList<myClass> myArr=new ArrayList<>();
for(int i=0;i<indexes.length;i++) {
myArr.add(new myClass(indexes[i], sources[i], targets[i]));
}
//Collections.sort(myArr,new compareIndex());
// Just for readability of code
Collections.sort(myArr, (mC1, mC2) -> mC1.getX() - mC2.getX());
//Conversion Part
for (int i=0;i<myArr.size();i++){
indexes[i]=myArr.get(i).getX();
sources[i]=myArr.get(i).getSource();
targets[i]=myArr.get(i).getTarget();
}
System.out.println(Arrays.toString(indexes));
System.out.println(Arrays.toString(sources));
System.out.println(Arrays.toString(targets));
}
}
class myClass {
private Integer x;
private String source;
private String target;
public myClass(Integer x,String source,String target){
this.x=x;
this.source=source;
this.target=target;
}
public Integer getX() {
return x;
}
public String getSource() {
return source;
}
public String getTarget() {
return target;
}
}
Related
I have searched for a way to resize an array in Java, but I could not find ways of resizing the array while keeping the current elements.
I found for example code like int[] newImage = new int[newWidth];, but this deletes the elements stored before.
My code would basically do this: whenever a new element is added, the array largens by 1. I think this could be done with dynamic programming, but I'm, not sure how to implement it.
You can't resize an array in Java. You'd need to either:
Create a new array of the desired size, and copy the contents from the original array to the new array, using java.lang.System.arraycopy(...);
Use the java.util.ArrayList<T> class, which does this for you when you need to make the array bigger. It nicely encapsulates what you describe in your question.
Use java.util.Arrays.copyOf(...) methods which returns a bigger array, with the contents of the original array.
Not nice, but works:
int[] a = {1, 2, 3};
// make a one bigger
a = Arrays.copyOf(a, a.length + 1);
for (int i : a)
System.out.println(i);
as stated before, go with ArrayList
Here are a couple of ways to do it.
Method 1: System.arraycopy():
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array. A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest. The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in the source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
Object[] originalArray = new Object[5];
Object[] largerArray = new Object[10];
System.arraycopy(originalArray, 0, largerArray, 0, originalArray.length);
Method 2: Arrays.copyOf():
Copies the specified array, truncating or padding with nulls (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain null. Such indices will exist if and only if the specified length is greater than that of the original array. The resulting array is of exactly the same class as the original array.
Object[] originalArray = new Object[5];
Object[] largerArray = Arrays.copyOf(originalArray, 10);
Note that this method usually uses System.arraycopy() behind the scenes.
Method 3: ArrayList:
Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)
ArrayList functions similarly to an array, except it automatically expands when you add more elements than it can contain. It's backed by an array, and uses Arrays.copyOf.
ArrayList<Object> list = new ArrayList<>();
// This will add the element, resizing the ArrayList if necessary.
list.add(new Object());
You could just use ArrayList which does the job for you.
It is not possible to change the Array Size.
But you can copy the element of one array into another array by creating an Array of bigger size.
It is recommended to create Array of double size if Array is full and Reduce Array to halve if Array is one-half full
public class ResizingArrayStack1 {
private String[] s;
private int size = 0;
private int index = 0;
public void ResizingArrayStack1(int size) {
this.size = size;
s = new String[size];
}
public void push(String element) {
if (index == s.length) {
resize(2 * s.length);
}
s[index] = element;
index++;
}
private void resize(int capacity) {
String[] copy = new String[capacity];
for (int i = 0; i < s.length; i++) {
copy[i] = s[i];
s = copy;
}
}
public static void main(String[] args) {
ResizingArrayStack1 rs = new ResizingArrayStack1();
rs.push("a");
rs.push("b");
rs.push("c");
rs.push("d");
}
}
You could use a ArrayList instead of array. So that you can add n number of elements
List<Integer> myVar = new ArrayList<Integer>();
Standard class java.util.ArrayList is resizable array, growing when new elements added.
You can't resize an array, but you can redefine it keeping old values or use a java.util.List
Here follows two solutions but catch the performance differences running the code below
Java Lists are 450 times faster but 20 times heavier in memory!
testAddByteToArray1 nanoAvg:970355051 memAvg:100000
testAddByteToList1 nanoAvg:1923106 memAvg:2026856
testAddByteToArray1 nanoAvg:919582271 memAvg:100000
testAddByteToList1 nanoAvg:1922660 memAvg:2026856
testAddByteToArray1 nanoAvg:917727475 memAvg:100000
testAddByteToList1 nanoAvg:1904896 memAvg:2026856
testAddByteToArray1 nanoAvg:918483397 memAvg:100000
testAddByteToList1 nanoAvg:1907243 memAvg:2026856
import java.util.ArrayList;
import java.util.List;
public class Test {
public static byte[] byteArray = new byte[0];
public static List<Byte> byteList = new ArrayList<>();
public static List<Double> nanoAvg = new ArrayList<>();
public static List<Double> memAvg = new ArrayList<>();
public static void addByteToArray1() {
// >>> SOLUTION ONE <<<
byte[] a = new byte[byteArray.length + 1];
System.arraycopy(byteArray, 0, a, 0, byteArray.length);
byteArray = a;
//byteArray = Arrays.copyOf(byteArray, byteArray.length + 1); // the same as System.arraycopy()
}
public static void addByteToList1() {
// >>> SOLUTION TWO <<<
byteList.add(new Byte((byte) 0));
}
public static void testAddByteToList1() throws InterruptedException {
System.gc();
long m1 = getMemory();
long n1 = System.nanoTime();
for (int i = 0; i < 100000; i++) {
addByteToList1();
}
long n2 = System.nanoTime();
System.gc();
long m2 = getMemory();
byteList = new ArrayList<>();
nanoAvg.add(new Double(n2 - n1));
memAvg.add(new Double(m2 - m1));
}
public static void testAddByteToArray1() throws InterruptedException {
System.gc();
long m1 = getMemory();
long n1 = System.nanoTime();
for (int i = 0; i < 100000; i++) {
addByteToArray1();
}
long n2 = System.nanoTime();
System.gc();
long m2 = getMemory();
byteArray = new byte[0];
nanoAvg.add(new Double(n2 - n1));
memAvg.add(new Double(m2 - m1));
}
public static void resetMem() {
nanoAvg = new ArrayList<>();
memAvg = new ArrayList<>();
}
public static Double getAvg(List<Double> dl) {
double max = Collections.max(dl);
double min = Collections.min(dl);
double avg = 0;
boolean found = false;
for (Double aDouble : dl) {
if (aDouble < max && aDouble > min) {
if (avg == 0) {
avg = aDouble;
} else {
avg = (avg + aDouble) / 2d;
}
found = true;
}
}
if (!found) {
return getPopularElement(dl);
}
return avg;
}
public static double getPopularElement(List<Double> a) {
int count = 1, tempCount;
double popular = a.get(0);
double temp = 0;
for (int i = 0; i < (a.size() - 1); i++) {
temp = a.get(i);
tempCount = 0;
for (int j = 1; j < a.size(); j++) {
if (temp == a.get(j))
tempCount++;
}
if (tempCount > count) {
popular = temp;
count = tempCount;
}
}
return popular;
}
public static void testCompare() throws InterruptedException {
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 20; i++) {
testAddByteToArray1();
}
System.out.println("testAddByteToArray1\tnanoAvg:" + getAvg(nanoAvg).longValue() + "\tmemAvg:" + getAvg(memAvg).longValue());
resetMem();
for (int i = 0; i < 20; i++) {
testAddByteToList1();
}
System.out.println("testAddByteToList1\tnanoAvg:" + getAvg(nanoAvg).longValue() + "\t\tmemAvg:" + getAvg(memAvg).longValue());
resetMem();
}
}
private static long getMemory() {
Runtime runtime = Runtime.getRuntime();
return runtime.totalMemory() - runtime.freeMemory();
}
public static void main(String[] args) throws InterruptedException {
testCompare();
}
}
You can try below solution inside some class:
int[] a = {10, 20, 30, 40, 50, 61};
// private visibility - or change it as needed
private void resizeArray(int newLength) {
a = Arrays.copyOf(a, a.length + newLength);
System.out.println("New length: " + a.length);
}
It is not possible to resize an array. However, it is possible change the size of an array through copying the original array to the newly sized one and keep the current elements. The array can also be reduced in size by removing an element and resizing.
import java.util.Arrays
public class ResizingArray {
public static void main(String[] args) {
String[] stringArray = new String[2] //A string array with 2 strings
stringArray[0] = "string1";
stringArray[1] = "string2";
// increase size and add string to array by copying to a temporary array
String[] tempStringArray = Arrays.copyOf(stringArray, stringArray.length + 1);
// Add in the new string
tempStringArray[2] = "string3";
// Copy temp array to original array
stringArray = tempStringArray;
// decrease size by removing certain string from array (string1 for example)
for(int i = 0; i < stringArray.length; i++) {
if(stringArray[i] == string1) {
stringArray[i] = stringArray[stringArray.length - 1];
// This replaces the string to be removed with the last string in the array
// When the array is resized by -1, The last string is removed
// Which is why we copied the last string to the position of the string we wanted to remove
String[] tempStringArray2 = Arrays.copyOf(arrayString, arrayString.length - 1);
// Set the original array to the new array
stringArray = tempStringArray2;
}
}
}
}
Sorry, but at this time is not possible resize arrays, and may be never will be.
So my recommendation, is to think more to find a solution that allow you get from the beginning of the process, the size of the arrays that you will requiere. This often will implicate that your code need a little more time (lines) to run, but you will save a lot of memory resources.
We can't do that using array datatype. Instead use a growable array which is arrayList in Java.
As in the title, I want to use Knuth-Fisher-Yates shuffle algorithm to select N random elements from a List but without using List.toArray and change the list. Here is my current code:
public List<E> getNElements(List<E> list, Integer n) {
List<E> rtn = null;
if (list != null && n != null && n > 0) {
int lSize = list.size();
if (lSize > n) {
rtn = new ArrayList<E>(n);
E[] es = (E[]) list.toArray();
//Knuth-Fisher-Yates shuffle algorithm
for (int i = es.length - 1; i > es.length - n - 1; i--) {
int iRand = rand.nextInt(i + 1);
E eRand = es[iRand];
es[iRand] = es[i];
//This is not necessary here as we do not really need the final shuffle result.
//es[i] = eRand;
rtn.add(eRand);
}
} else if (lSize == n) {
rtn = new ArrayList<E>(n);
rtn.addAll(list);
} else {
log("list.size < nSub! ", lSize, n);
}
}
return rtn;
}
It uses list.toArray() to make a new array to avoid modifying the original list. However, my problem now is that my list could be very big, can have 1 million elements. Then list.toArray() is too slow. And my n could range from 1 to 1 million. When n is small (say 2), the function is very in-efficient as it still need to do list.toArray() for a list of 1 million elements.
Can someone help improve the above code to make it more efficient when dealing with large lists. Thanks.
Here I assume Knuth-Fisher-Yates shuffle is the best algorithm to do the job of selecting n random elements from a list. Am I right? I would be very glad to if there is other algorithms better than Knuth-Fisher-Yates shuffle to do the job in terms of the speed and the quality of the results (guarantee real randomness).
Update:
Here is some of my test results:
When selection n from 1000000 elements.
When n<1000000/4 the fastest way to through using Daniel Lemire's Bitmap function to select n random id first then get the elements with these ids:
public List<E> getNElementsBitSet(List<E> list, int n) {
List<E> rtn = new ArrayList<E>(n);
int[] ids = genNBitSet(n, 0, list.size());
for (int i = 0; i < ids.length; i++) {
rtn.add(list.get(ids[i]));
}
return rtn;
}
The genNBitSet is using the code generateUniformBitmap from https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2013/08/14/java/UniformDistinct.java
When n>1000000/4 the Reservoir Sampling method is faster.
So I have built a function to combine these two methods.
You are probably looking for something like Resorvoir Sampling.
Start with an initial array with first k elements, and modify it with new elements with decreasing probabilities:
java like pseudo code:
E[] r = new E[k]; //not really, cannot create an array of generic type, but just pseudo code
int i = 0;
for (E e : list) {
//assign first k elements:
if (i < k) { r[i++] = e; continue; }
//add current element with decreasing probability:
j = random(i++) + 1; //a number from 1 to i inclusive
if (j <= k) r[j] = e;
}
return r;
This requires a single pass on the data, with very cheap ops every iteration, and the space consumption is linear with the required output size.
If n is very small compared to the length of the list, take an empty set of ints and keep adding a random index until the set has the right size.
If n is comparable to the length of the list, do the same, but then return items in the list that don't have indexes in the set.
In the middle ground, you can iterate through the list, and randomly select items based on how many items you've seen, and how many items you've already returned. In pseudo-code, if you want k items from N:
for i = 0 to N-1
if random(N-i) < k
add item[i] to the result
k -= 1
end
end
Here random(x) returns a random number between 0 (inclusive) and x (exclusive).
This produces a uniformly random sample of k elements. You could also consider making an iterator to avoid building the results list to save memory, assuming the list is unchanged as you're iterating over it.
By profiling, you can determine the transition point where it makes sense to switch from the naive set-building method to the iteration method.
Let's assume that you can generate n random indices out of m that are pairwise disjoint and then look them up efficiently in the collection. If you don't need the order of the elements to be random, then you can use an algorithm due to Robert Floyd.
Random r = new Random();
Set<Integer> s = new HashSet<Integer>();
for (int j = m - n; j < m; j++) {
int t = r.nextInt(j);
s.add(s.contains(t) ? j : t);
}
If you do need the order to be random, then you can run Fisher--Yates where, instead of using an array, you use a HashMap that stores only those mappings where the key and the value are distinct. Assuming that hashing is constant time, both of these algorithms are asymptotically optimal (though clearly, if you want to randomly sample most of the array, then there are data structures with better constants).
Just for convenience: A MCVE with an implementation of the Resorvoir Sampling proposed by amit (possible upvotes should go to him (I'm just hacking some code))
It seems like this is indeed a algorithm that nicely covers the cases of where the number of elements to select is low compared to the list size, and the cases where the number of elements is high compared to the list size (assumung that the properties about the randomness of the result that are stated on the wikipedia page are correct).
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;
public class ReservoirSampling
{
public static void main(String[] args)
{
example();
//test();
}
private static void test()
{
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
int size = 2;
int runs = 100000;
Map<String, Integer> counts = new TreeMap<String, Integer>();
for (int i=0; i<runs; i++)
{
List<String> sample = sample(list, size);
String s = createString(sample);
Integer count = counts.get(s);
if (count == null)
{
count = 0;
}
counts.put(s, count+1);
}
for (Entry<String, Integer> entry : counts.entrySet())
{
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
private static String createString(List<String> list)
{
Collections.sort(list);
StringBuilder sb = new StringBuilder();
for (String s : list)
{
sb.append(s);
}
return sb.toString();
}
private static void example()
{
List<String> list = new ArrayList<String>();
for (int i=0; i<26; i++)
{
list.add(String.valueOf((char)('A'+i)));
}
for (int i=1; i<=26; i++)
{
printExample(list, i);
}
}
private static <T> void printExample(List<T> list, int size)
{
System.out.printf("%3d elements: "+sample(list, size)+"\n", size);
}
private static final Random random = new Random(0);
private static <T> List<T> sample(List<T> list, int size)
{
List<T> result = new ArrayList<T>(Collections.nCopies(size, (T) null));
int i = 0;
for (T element : list)
{
if (i < size)
{
result.set(i, element);
i++;
continue;
}
i++;
int j = random.nextInt(i);
if (j < size)
{
result.set(j, element);
}
}
return result;
}
}
If n is way smaller then size, you could use this algorith, witch is unfortunatly quadratic with n, but doest depend on size of array at all.
Example with size = 100 and n = 4.
choose random number from 0 to 99, lets say 42, and add it to result.
choose random number from 0 to 98, lets say 39, and add it to result.
choose random number from 0 to 97, lets say 41, but since 41 is bigger or equal than 39, increment it by 1, so you have 42, but that is bigger then equal than 42, so you have 43.
...
Shortly, you choose from remaining numbers and then compuce what number have you acctualy chosen. I would use link list for this, but maybe there are better data structures.
Summarizing Changwang's update. If you want more than 250,000 items, use amit's answer. Otherwise use Knuth-Fisher-Yates Shuffle as shown in entirety here
NOTE: The result is always in the original order as well
public static <T> List<T> getNRandomElements(int n, List<T> list) {
List<T> subList = new ArrayList<>(n);
int[] ids = generateUniformBitmap(n, list.size());
for (int id : ids) {
subList.add(list.get(id));
}
return subList;
}
// https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2013/08/14/java/UniformDistinct.java
private static int[] generateUniformBitmap(int num, int max) {
if (num > max) {
DebugUtil.e("Can't generate n ints");
}
int[] ans = new int[num];
if (num == max) {
for (int k = 0; k < num; ++k) {
ans[k] = k;
}
return ans;
}
BitSet bs = new BitSet(max);
int cardinality = 0;
Random random = new Random();
while (cardinality < num) {
int v = random.nextInt(max);
if (!bs.get(v)) {
bs.set(v);
cardinality += 1;
}
}
int pos = 0;
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
ans[pos] = i;
pos += 1;
}
return ans;
}
If you want them randomized, I use:
public static <T> List<T> getNRandomShuffledElements(int n, List<T> list) {
List<T> randomElements = getNRandomElements(n, list);
Collections.shuffle(randomElements);
return randomElements;
}
I needed something for this in C#, here's my solution which works on a generic List.
It selects N random elements of the list and places them at the front of the list.
So upon returning, the first N elements of the list are randomly selected. It is fast and efficient even when you're dealing with a very large number of elements.
static void SelectRandom<T>(List<T> list, int n)
{
if (n >= list.Count)
{
// n should be less than list.Count
return;
}
int max = list.Count;
var random = new Random();
for (int i = 0; i < n; i++)
{
int r = random.Next(max);
max = max - 1;
int irand = i + r;
if (i != irand)
{
T rand = list[irand];
list[irand] = list[i];
list[i] = rand;
}
}
}
How might I approach solving the following problem:
Create an array of integers that are contained in at least two of the given arrays.
For example:
int[] a1 = new int[] { 1, 2, 3, 4, 5 };
int[] a2 = new int[] { 5, 10, 11, 8 };
int[] a3 = new int[] { 1, 7, 6, 4, 5, 3, 11 };
must give a result array
int[] result = new int[] {1, 3, 4, 5, 11}
P.S. i'm interested in suggestions on how I might approach this ("algorithm"), not what Java utils might give me the answer
put a1 numbers in a Map<Integer,Integer> count, using the value as the key, and setting the count to 1
Put a2 numbers into the same map. If an item does not exist, assign the count of 1, otherwise assign it the existing count + 1
Put a3 numbers into the same map. If an item does not exist, assign the count of 1, otherwise assign it the existing count + 1
Go through the entries in a map, and output all keys where the value is greater than one.
This algorithm is amortized linear time in the combined number of elements in the three arrays.
If the numbers in the three arrays are limited to, say, 1000 or another relatively small number, you could avoid using collections at all, but use a potentially more expensive algorithm based on the upper limit of your numbers: replace the map with an array counts[MAX_NUM+1], and then run the same algorithm, like this:
int[] counts = new int[MAX_NUM+1];
for (int a : a1) counts[a]++;
for (int a : a2) counts[a]++;
for (int a : a3) counts[a]++;
for (int i = 0 ; i != MAX_NUM+1 ; i++) {
if (counts[i] > 1) {
System.out.println(i);
}
}
You can look at the 3 arrays as sets and find each element that is in the intersection of some pair of sets.
basically, you are looking for (set1 [intersection] set2) [union] (set2 [intersection] set3) [union] (set1 [intersection] set2)
I agree that it might not be the easiest way to achieve what you are after, but being able to reduce one problem to another is a technique every programmer should master, and this solution should be very educating.
The only way to do this without collections would be to take an element from an array, iterate over the remaining two arrays to see if a duplicate is found (and then break and move to the next element). You need to do this for two out of the three arrays as by the time you move to the third one, you would already have your answer.
Mathematically this can be solved as follows:
You can construct three sets using each of the three arrays, so duplicated entries in each array will only occur once in each set. And then the entries that appear at least in two of the three sets are solutions. So they are given by
(S_1 intersect S_2) union (S_2 intersect S_3) union (S_3 intersect S_1)
Think about the question and the different strategies you might use:
Go through each entry in each array, if that entry is NOT already in the "duplicates" result, then see if that entry is in each of the remaining arrays. Add to duplicates if it is and return to next integer
Create an array of non-duplicates by adding an entry from each array (and if it is already there, putting it in the duplicates array).
Use another creative strategy of your own
I like drawing Venn diagramms. You know that diagram with three intersecting circles, e.g. see here.
You then see that the complement is easier to describe:
Those elements which only exist in one array, are not interesting.
So you could build a frequency list (i.e. key = element, value = count of in how many arrays you found it [for the first time]) in a hash map, and then in a final pass pick all elements which occured more than once.
For simplicity I used sets. If your arrays contain multiple entries of the same value, you have to ignore those extra occurences when you build the frequency list.
An approach could be like this:
1.Sort all the arrays.
2.For each combination of arrays do this
Let us consider the first two arrays A,B. Let a be A's size.
Also take a third array or vector to store our result
for i=0-->a-1 {
Search for A[i] in B using binarySearch.
if A[i] exists in B then insert A[i] into our result vector
}
Repeat the same process for (B,C) and (C,A).
Now sort & Traverse the result vector from the end, remove the elements which have the property
result[i] = result[i-1]
The final vector is the required result.
Time Complexity Analysis:
T(n) = O(nlog(n)) for Sorting where n is the highest array size among the given three
For searching each element of an array in other sorted array T(n) = n * O(log n)
T(n) = O(n (log n)) for sorting the result and O(n) for traversing
So overall time complexity is O(n log(n)); and space complexity is O(n)
Please correct me of I am wrong
In Java:
Will write one without using java.utils shortly.
Meantime a solution using java.utils:
public static void twice(int[] a, int[] b, int[] c) {
//Used Set to remove duplicates
Set<Integer> setA = new HashSet<Integer>();
for (int i = 0; i < a.length; i++) {
setA.add(a[i]);
}
Set<Integer> setB = new HashSet<Integer>();
for (int i = 0; i < b.length; i++) {
setB.add(b[i]);
}
Set<Integer> setC = new HashSet<Integer>();
for (int i = 0; i < c.length; i++) {
setC.add(c[i]);
}
//Logic to fill data into a Map
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer val : setA) {
map.put(val, 1);
}
for (Integer val : setB) {
if (map.get(val) != null) {
int count = map.get(val);
count++;
map.put(val, count);
} else {
map.put(val, 1);
}
}
for (Integer val : setC) {
if (map.get(val) != null) {
int count = map.get(val);
count++;
map.put(val, count);
} else {
map.put(val, 1);
}
}
for (Map.Entry<Integer, Integer> entry2 : map.entrySet()) {
//if (entry2.getValue() == 2) { //Return the elements that are present in two out of three arrays.
if(entry2.getValue() >= 2) { //Return elements that are present **at least** twice in the three arrays.
System.out.print(" " + entry2.getKey());
}
}
}
Change condition in last for loop in case one need to return the elements that are present in two out of three arrays. Say:
int[] a = { 2, 3, 8, 4, 1, 9, 8 };
int[] b = { 6, 5, 3, 7, 9, 2, 1 };
int[] c = { 5, 1, 8, 2, 4, 0, 5 };
Output: { 3, 8, 4, 5, 9 }
Here goes without any java.util library:
public static void twice(int[] a, int[] b, int[] c) {
int[] a1 = removeDuplicates(a);
int[] b1 = removeDuplicates(b);
int[] c1 = removeDuplicates(c);
int totalLen = a1.length + b1.length +c1.length;
int[][] keyValue = new int[totalLen][2];
int index = 0;
for(int i=0; i<a1.length; i++, index++)
{
keyValue[index][0] = a1[i]; //Key
keyValue[index][1] = 1; //Value
}
for(int i=0; i<b1.length; i++)
{
boolean found = false;
int tempIndex = -1;
for(int j=0; j<index; j++)
{
if (keyValue[j][0] == b1[i]) {
found = true;
tempIndex = j;
break;
}
}
if(found){
keyValue[tempIndex][1]++;
} else {
keyValue[index][0] = b1[i]; //Key
keyValue[index][1] = 1; //Value
index++;
}
}
for(int i=0; i<c1.length; i++)
{
boolean found = false;
int tempIndex = -1;
for(int j=0; j<index; j++)
{
if (keyValue[j][0] == c1[i]) {
found = true;
tempIndex = j;
break;
}
}
if(found){
keyValue[tempIndex][1]++;
} else {
keyValue[index][0] = c1[i]; //Key
keyValue[index][1] = 1; //Value
index++;
}
}
for(int i=0; i<index; i++)
{
//if(keyValue[i][1] == 2)
if(keyValue[i][1] >= 2)
{
System.out.print(keyValue[i][0]+" ");
}
}
}
public static int[] removeDuplicates(int[] input) {
boolean[] dupInfo = new boolean[500];//Array should not have any value greater than 499.
int totalItems = 0;
for( int i = 0; i < input.length; ++i ) {
if( dupInfo[input[i]] == false ) {
dupInfo[input[i]] = true;
totalItems++;
}
}
int[] output = new int[totalItems];
int j = 0;
for( int i = 0; i < dupInfo.length; ++i ) {
if( dupInfo[i] == true ) {
output[j++] = i;
}
}
return output;
}
It's very simple and could be done for n different arrays the same way:
public static void compute(int[] a1, int[] a2, int[] a3) {
HashMap<Integer, Integer> map = new HashMap<>();
fillMap(map, a1);
fillMap(map, a2);
fillMap(map, a3);
for (Integer key : map.keySet()) {
System.out.print(map.get(key) > 1 ? key + ", " : "");
}
}
public static void fillMap(HashMap<Integer, Integer> map, int[] a) {
for (int i : a) {
if (map.get(i) == null) {
map.put(i, 1);
continue;
}
int count = map.get(i);
map.put(i, ++count);
}
}
fun atLeastTwo(a: ArrayList<Int>, b: ArrayList<Int>, c: ArrayList<Int>): List<Int>{
val map = a.associateWith { 1 }.toMutableMap()
b.toSet().forEach { map[it] = map.getOrDefault(it, 0) + 1 }
c.toSet().forEach{ map[it] = map.getOrDefault(it, 0) + 1 }
return map.filter { it.value == 2 }.map { it.key }
}
In Javascript you can do it like this:
let sa = new Set(),
sb = new Set(),
sc = new Set();
A.forEach(a => sa.add(a));
B.forEach(b => sb.add(b));
C.forEach(c => sc.add(c));
let res = new Set();
sa.forEach((a) => {
if (sb.has(a) || sc.has(a)) res.add(a);
})
sb.forEach((b) => {
if (sa.has(b) || sc.has(b)) res.add(b);
})
sc.forEach((c) => {
if (sa.has(c) || sb.has(c)) res.add(c);
})
let arr = Array.from(res.values());
arr.sort((i, j) => i - j)
return arr
I have an array of numbers and I need the biggest of three number with respective index value. I have an array like this:
int [] value = new int[5];
value[0] = 8;
value[1] = 3;
value[2] = 5;
value[3] = 2;
value[4] = 7;
How to find the largest numbers and their index values?
I suspsect this is homework, so I'm going to give some help, but not a full solution.
You need the biggest three numbers, as well as their index values?
Well, walk over the array, keeping track of the highest three numbers you have found so far. Also keep track of their index numbers.
You could start by doing this for only the biggest number and its index. That should be easy.
It takes two variables, e.g. BiggestNumber and indexOfBiggestNumber. Start with finding the biggest number (trivial), then add some code to remember it's index.
Once you have that, you can add some more code to keep track of the second biggest number and it's index as well.
After that, you do the same for the third biggest number.
I have done it for you, and this works.
here goes the complete code:
import java.util.Arrays;
class tester {
public static void main(String[] args) {
int[] value = new int[5];
value[0] = 8;
value[1] = 3;
value[2] = 5;
value[3] = 2;
value[4] = 7;
int size = value.length;
int[] temp = (int[]) value.clone();
Arrays.sort(temp);
for (int i = 0; i < 3; i++) {
System.out.println("value: " + temp[size - (i + 1)] +
" index " + getIndex(value, temp[size - (i + 1)]));
}
}
static int getIndex(int[] value, int v) {
int temp = 0;
for (int i = 0; i < value.length; i++) {
if (value[i] == v) {
temp = i;
break;
}
}
return temp;
}
}
No need to traverse through array and keep tracking of so many variables , you can take advantage of already implemented methods like below.
I would suggest to use a List of Map.Entry<key,value > (where key=index and value=number) and then implement Comparator interface with overridden compare method (to sort on values). Once you have implemented it just sort the list .
public static void main(String[] args) {
int[] value = {5, 3, 12, 12, 7};
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int k = 0; k < value.length; k++)
map.put(k, value[k]);
List<Map.Entry<Integer, Integer>> list =
new LinkedList<Map.Entry<Integer, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
#Override
public int compare(
Entry<Integer, Integer> e1,
Entry<Integer, Integer> e2) {
return e2.getValue().compareTo(e1.getValue());
}
});
for (Entry<Integer, Integer> lValue : list)
System.out.println("value = " + lValue.getValue()
+ " , Index = " + lValue.getKey());
}
Results:
value = 12 , Index = 2
value = 12 , Index = 3
value = 7 , Index = 4
value = 5 , Index = 0
value = 3 , Index = 1
By this approach you can get top N largest numbers with their index.
To get the three biggest, basically, you sort, and pick the last three entries.
Getting their indexes takes a little more work, but is definitely doable. Simply bundle the number and its index together in a Comparable whose compareTo function only cares about the number. Sort, get the last three items, and now you have each number and its index.
class IntWithIndex implements Comparable<IntWithIndex> {
public int number, index;
public IntWithIndex(number, index) {
this.number = number;
this.index = index;
}
public int compareTo(IntWithIndex other) {
return number - other.number;
}
}
...
IntWithIndex iwi[] = new IntWithIndex[yourNumbers.length];
for (int i = 0; i < yourNumbers.length; ++i) {
iwi[i] = new IntWithIndex(yourNumbers[i], i);
}
Arrays.sort(iwi);
int largest = iwi[iwi.length - 1].number;
int largestIndex = iwi[iwi.length - 1].index;
// and so on
Sort the array in descending order and show the first 3 element.
How can we find out missing elements from two arrays ?
Ex:
int []array1 ={1,2,3,4,5};
int []array2 ={3,1,2};
From the above two arrays i want to find what are the missing elements in second array?
Convert them to Sets and use removeAll.
The first problem is how to convert a primitive int[] to a collection.
With Guava you can use:
List<Integer> list1 = Ints.asList(array1);
List<Integer> list2 = Ints.asList(array2);
Apache commons (which I'm not familiar with) apparently has something similar.
Now convert to a set:
Set<Integer> set1 = new HashSet<Integer>(list1);
And compute the difference:
set1.removeAll(list2);
And convert the result back to an array:
return Ints.toArray(set1);
If you are allowed duplicates in the arrays, an efficient (O(n)) solution it to create a frequency table (Map) by iterating over the first array, and then use the map to match off any elements in the second array.
Map<Integer, Integer> freqMap = new HashMap<Integer, Integer>();
// Iterate over array1 and populate frequency map whereby
// the key is the integer and the value is the number of
// occurences.
for (int val1 : array1) {
Integer freq = freqMap.get(val1);
if (freq == null) {
freqMap.put(val1, 1);
} else {
freqMap.put(val1, freq + 1);
}
}
// Now read the second array, reducing the frequency for any value
// encountered that is also in array1.
for (int val2 : array2) {
Integer freq = freqMap.get(val2);
if (freq == null) {
freqMap.remove(val2);
} else {
if (freq == 0) {
freqMap.remove(val2);
} else {
freqMap.put(freq - 1);
}
}
}
// Finally, iterate over map and build results.
List<Integer> result = new LinkedList<Integer>();
for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
int remaining = entry.getValue();
for (int i=0; i<remaining; ++i) {
result.add(entry.getKey());
}
}
// TODO: Convert to int[] using the util. method of your choosing.
Simple logic for getting the unmatched numbers.
public static int getelements(int[] array1, int[] array2)
{
int count = 0;
ArrayList unMatched = new ArrayList();
int flag = 0;
for(int i=0; i<array1.length ; i++)
{ flag=0;
for(int j=0; j<array2.length ; j++)
{
if(array1[i] == array2[j]) {
flag =1;
break;
}
}
if(flag==0)
{
unMatched.add(array1[i]);
}
}
System.out.println(unMatched);
return unMatched.size();
}
public static void main(String[] args) {
// write your code here5
int array1[] = {7,3,7,2,8,3,2,5};
int array2[] = {7,4,9,5,5,10,4};
int count;
count = getelements(array1,array2);
System.out.println(count);
}
You can use Set and its methods. This operation would be a set difference.
The naive way would be to simply search one array for each of the elements of the other array (with a for loop). If you first were to SORT both arrays, it becomes much more efficient.
Consider using intersection method:
A healthy discussion is available at:
http://www.coderanch.com/t/35439/Programming-Diversions/Intersection-two-arrays
You could create two other int arrays to store the multiplicity of each value. Increment the index of the array that the value corresponds with every time it is found and then compare the arrays.
It's not the most "efficient" way perhaps, but it's a very simple concept that works.
Guava library can be helpful; you need to change Array in Set then can use API.
#finnw I believe you were thinking of commons-collections.
Need to import org.apache.commons.collections.CollectionUtils;
To get the disjunction function.
Using the disjunction method will find all objects that aren't found in an intersection.
Integer[] array1 ={1,2,3,4,5};
Integer[] array2 ={3,1,2};
List list1 = Arrays.asList(array1);
List list2 = Arrays.asList(array2);
Collection result = CollectionUtils.disjunction(list1, list2);
System.out.println(result); // displays [4, 5]
This is not the most efficient way but it's probably the simplest way that works in Java :
public static void main(final String[] args) {
final int[] a = { 1, 2, 3, 4, 5 };
final int[] b = { 3, 1, 2 };
// we have to do this just in case if there might some values that are missing in a and b
// example: a = { 1, 2, 3, 4, 5 }; b={ 2, 3, 1, 0, 5 }; missing value=4 and 0
findMissingValue(b, a);
findMissingValue(a, b);
}
private static void findMissingValue(final int[] x, final int[] y) {
// loop through the bigger array
for (final int n : x) {
// for each value in the a array call another loop method to see if it's in there
if (!findValueSmallerArray(n, y)) {
System.out.println("missing value: " + n);
// break;
}
}
}
private static boolean findValueSmallerArray(final int n, final int[] y) {
for (final int i : y) {
if (n == i) {
return true;
}
}
return false;
}