This is the requirement where I am facing problem finding the solution.
Problem:
I have ArrayList with data 20, 10, 30, 50, 40, 10.
If we sort this in ascending order the result will be 10, 10, 20, 30, 40, 50.
But I need the result as 3, 1, 4, 6, 5, 2.(The index of each element after sorting).
Strictly this should work even if there are repetitive elements in the list.
Please share your idea/approach solving this problem.
Here is my solution. We define a comparator to sort a list of indices based on the corresponding object in the list. That gives us a list of indices which is effectively a map: indices[i] = x means that the element at location x in the original list is at element i in the sorted list. We can then create a reverse mapping easily enough.
Output is the indices starting from 0: [2, 0, 3, 5, 4, 1]
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class LookupComparator<T extends Comparable<T>> implements Comparator<Integer> {
private ArrayList<T> _table;
public LookupComparator(ArrayList<T> table) {
_table = table;
}
public int compare(Integer o1, Integer o2) {
return _table.get(o1).compareTo(_table.get(o2));
}
}
public class Test {
public static <T extends Comparable<T>> ArrayList<Integer> indicesIfSorted(ArrayList<T> list) {
ArrayList<Integer> indices = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++)
indices.add(i);
Collections.sort(indices, new LookupComparator(list));
ArrayList<Integer> finalResult = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++)
finalResult.add(0);
for (int i = 0; i < list.size(); i++)
finalResult.set(indices.get(i), i);
return finalResult;
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(20);
list.add(10);
list.add(30);
list.add(50);
list.add(40);
list.add(10);
ArrayList<Integer> indices = indicesIfSorted(list);
System.out.println(indices);
}
}
My idea is creating 1 more attribute call index beside your value (in each data of aray). It will hold your old index, then u can take it out for using.
Building off what Hury said, I think the easiest way I can see to do this is to make a new data type that looks something like:
public class Foo {
private Integer value;
private int origPosition;
private int sortedPosition;
/*Constructors, getters, setters, etc... */
}
And some psuedo code for what to do with it...
private void printSortIndexes(ArrayList<Integer> integerList) {
// Create an ArrayList<Foo> from integerList - O(n)
// Iterate over the list setting the origPosition on each item - O(n)
// Sort the list based on value
// Iterate over the list setting the sortedPosition on each item - O(n)
// Resort the list based on origPositon
// Iterate over the lsit and print the sortedPositon - O(n)
}
That won't take long to implement, but it is horribly inefficient. You are throwing in an extra 4 O(n) operations, and each time you add or remove anything from your list, all the positions stored in the objects are invalidated - so you'd have to recaculate everything. Also it requires you to sort the list twice.
So if this is a one time little problem with a small-ish data set it will work, but if you trying to make something to use for a long time, you might want to try to think of a more elegant way to do it.
Here is the approach of adding an index to each element, written out in Scala. This approach makes the most sense.
list.zipWithIndex.sortBy{ case (elem, index) => elem }
.map{ case (elem, index) => index }
In Java you would need to create a new object that implements comperable.
class IndexedItem implements Comparable<IndexedItem> {
int index;
int item;
public int compareTo(IndexItem other) {
return this.item - other.item;
}
}
You could then build a list of IndexedItems, sort it with Collection.sort, and then pull out the indices.
You could also use Collections.sort on the original list followed by calls to indexOf.
for (int elem : originalList) {
int index = newList.indexOf(elem);
newList.get(index) = -1; // or some other value that won't be found in the list
indices.add(index);
}
This would be very slow (all the scans of indexOf), but would get the job done if you only need to do it a few times.
A simplistic approach would be to sort the list; then loop on the original list, find the index of the element in the sorted list and insert that into another list.
so a method like
public List<Integer> giveSortIndexes(List<Integer> origList) {
List<Integer> retValue = new ArrayList<Integer>();
List<Integer> originalList = new ArrayList<Integer>(origList);
Collections.sort(origList);
Map<Integer, Integer> duplicates = new HashMap<Integer, Integer>();
for (Integer i : originalList) {
if(!duplicates.containsKey(i)) {
retValue.add(origList.indexOf(i) + 1);
duplicates.put(i, 1);
} else {
Integer currCount = duplicates.get(i);
retValue.add(origList.indexOf(i) + 1 + currCount);
duplicates.put(i, currCount + 1);
}
}
return retValue;
}
I haven't tested the code and it might need some more handling for duplicates.
Related
In certain machine learning algorithms the columns of the matrix are rotated and sorted based relevance of each column. New data to come should be transformed in the same order. So if my initial sort gives me [0,2,1,3] as an index array, than new data should also be ordered in this way: first, third, second, fourth element. That's why I wanted to create a sorted index array, that could later on be used as a source for reordering new data. I've managed to do that in the implementation below.
My question is about the use of the index array for reoordering new data. In my implementation I first create a clone of the new data array. Than it's easy to just copy elements from my source array to the proper index in the target array. Is this the most efficient way to do it? Or is there a more efficient way, for instance by sorting the data in place?
import java.util.stream.*;
import java.util.*;
public class IndexSorter<T> {
private final int[] indices;
private final int[] reverted;
public IndexSorter(T[] data, Comparator<T> comparator){
// generate index array based on initial data and a comparator:
indices = IntStream.range(0, data.length)
.boxed()
.sorted( (a, b) -> comparator.compare(data[a],data[b]))
.mapToInt(a -> a)
.toArray();
// also create an index array to be able to revert the sort
reverted = new int[indices.length];
for(int i=0;i<indices.length;i++){
reverted[indices[i]] = i;
}
}
// sort new data based on initial array
public T[] sort(T[] data){
return sortUsing(data, indices);
}
// revert sorted data
public T[] revert(T[] data){
return sortUsing(data, reverted);
}
private T[] sortUsing(T[] data, int[] ind){
if(data.length != indices.length){
throw new IllegalArgumentException(
String.format("Data length does not match: (%s, should be: %s) "
, data.length, indices.length));
}
// create a copy of the data (efficively this just creates a new array)
T[] sorted = data.clone();
// fill the copy with the sorted data
IntStream.range(0, ind.length)
.forEach(i -> sorted[i]=data[ind[i]]);
return sorted;
}
}
class App {
public static void main(String args[]){
IndexSorter<String> sorter = new IndexSorter<>(args, String::compareTo);
String[] data = sorter.sort(args);
System.out.println(Arrays.toString(data));
data = sorter.revert(data);
System.out.println(Arrays.toString(data));
data = IntStream.range(0, data.length)
.mapToObj(Integer::toString)
.toArray(String[]::new);
data = sorter.sort(data);
System.out.println(Arrays.toString(data));
data = sorter.revert(data);
System.out.println(Arrays.toString(data));
}
}
I would not recommend copying data. Because this is a memory allocation that can be quite expensive. It is much more efficient to sort data in place with library methods, like as Arrays.sort
I've found a way to sort in place, using a BitSet to keep track of what indexes are having the right element. It is in the method sortUsing. I hope someone will have a use for this algorithm.
You can test it like this:
java App this is just some random test to show the result
Then outcome will first show you the sorted result, than the reverted result.
The same index array is also used for ordering an int array of indexes, and the reverted version:
[is, just, random, result, show, some, test, the, this, to]
[this, is, just, some, random, test, to, show, the, result]
[1, 2, 4, 9, 7, 3, 5, 8, 0, 6]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Here is the code:
import java.util.stream.*;
import java.util.*;
public class IndexSorter<T> {
private final int[] indices;
private final int[] reverted;
private final BitSet done;
public IndexSorter(T[] data, Comparator<T> comparator){
// generate index array based on initial data and a comparator:
indices = IntStream.range(0, data.length)
.boxed()
.sorted( (a, b) -> comparator.compare(data[a],data[b]))
.mapToInt(a -> a)
.toArray();
// also create an index array to be able to revert the sort
reverted = new int[indices.length];
for(int i=0;i<indices.length;i++){
reverted[indices[i]] = i;
}
done = new BitSet(data.length);
}
// sort new data based on initial array
public void sort(T[] data){
sortUsing(data, indices);
}
// revert sorted data
public void revert(T[] data){
sortUsing(data, reverted);
}
private void sortUsing(T[] data, int[] ind){
if(data.length != indices.length){
throw new IllegalArgumentException(
String.format("Data length does not match: (%s, should be: %s) "
, data.length, indices.length));
}
int ia=0, ib=0, x = 0;
T a = null, b = null;
for (int i=0; i< data.length && done.cardinality()<data.length; i++){
ia = i;
ib = ind[ia];
if(done.get(ia)){ // index is already done
continue;
}
if(ia==ib){ // element is at the right place
done.set(ia);
continue;
}
x = ia; // start a loop at x = ia
// some next index will be x again eventually
a = data[ia]; // keep element a as the last value after the loop
while(ib!=x && !done.get(ia) ){
b = data[ib]; // element from index b must go to index a
data[ia]=b;
done.set(ia);
ia = ib;
ib = ind[ia]; // get next index
}
data[ia]=a; // set value a to last index
done.set(ia);
}
done.clear();
}
}
class App {
public static void main(String args[]){
IndexSorter<String> sorter = new IndexSorter<>(args, String::compareTo);
sorter.sort(args);
System.out.println(Arrays.toString(args));
sorter.revert(args);
System.out.println(Arrays.toString(args));
String[] data = IntStream.range(0, args.length)
.mapToObj(Integer::toString)
.toArray(String[]::new);
sorter.sort(data);
System.out.println(Arrays.toString(data));
sorter.revert(data);
System.out.println(Arrays.toString(data));
}
}
I have the following data in an ArrayList. Let's say it's a String ArrayList for convenience sake.
Mokey
MokeyBaby1
MokeyBaby2
MokeyBaby3
Dog
DogBaby1
DogBaby2
Cat
CatBaby1
I need to move the items that are related, together.
For example: Moving Monkey down. The new ArrayList would look like this.
Dog
DogBaby1
DogBaby2
Mokey
MokeyBaby1
MokeyBaby2
MokeyBaby3
Cat
CatBaby1
I already have a method that tells me which ArrayList indexes are related.
For example: getRelatedIndexes("Monkey") would return 0,1,2,3 for the original list.
I just need to know if there is an easy way to move all the items up or down an ArrayList together.
Thanks.
You could wrap your list in a reorderable list and implement your reordering through that - at least you wouldn't need to hack the main list. It would maintain the order in an array of ints which you can then move around at will. You could even maintain the same data in several different orders if you like.
public static class OrderedList<T> extends AbstractList<T> {
// The list I proxy.
private final List<T> it;
// The order.
private final int[] order;
public OrderedList(List<T> wrap) {
it = wrap;
order = new int[it.size()];
// Initially the same order.
for (int i = 0; i < order.length; i++) {
order[i] = i;
}
}
#Override
public T get(int index) {
return it.get(order[index]);
}
#Override
public int size() {
return it.size();
}
// TODO - Only moves up! Breaks on a down move.
public void move(int start, int length, int to) {
int[] move = new int[length];
// Copy it out.
System.arraycopy(order, start, move, 0, length);
// Shift it down.
System.arraycopy(order, start + length, order, start, to - start);
// Pull it back in.
System.arraycopy(move, 0, order, to, length);
}
}
public void test() {
List<String> t = Arrays.asList("Zero", "One", "Two", "Three", "Four", "Five");
OrderedList<String> ordered = new OrderedList(t);
System.out.println(ordered);
ordered.move(1, 2, 3);
System.out.println(ordered);
}
prints
[Zero, One, Two, Three, Four, Five]
[Zero, Three, Four, One, Two, Five]
Alternatively - use Collections.rotate and work out what sub-list should be rotated which way to achieve your move.
Perhaps this contains the solution you need (swap and/or rotate/sublist) - Moving items around in an ArrayList
You could search for items in your list, which fullfill your criteria and safe them into another temporary list. Then you use the addAll(int index, Collection<? extends E> c) method to add these elements again to the list. Then you do not have to use add(int index, E element) for every Element itsself.
The block shifting strategy can be achieved by
taking the elements out of the original list using List.remove(index) and adding into a new temporary array. Note this has to be done in reverse order otherwise the indexes will change as items are removed.
Adding the new temporary array into the desired location using List.addAll(index, collection)
list of indexes cloned in case it is being used elsewhere
Example
public static void main(String[] args) {
List<Animal> animals = new ArrayList<Animal>(Arrays.asList(new Animal(
"Mokey"), new Animal("MokeyBaby1"), new Animal("MokeyBaby2"),
new Animal("MokeyBaby3"), new Animal("Dog"), new Animal(
"DogBaby1"), new Animal("DogBaby2"), new Animal("Cat"),
new Animal("CatBaby1")));
int[] relatedIndexes= { 0, 1, 2, 3 };
shift(animals, relatedIndexes, 3);
System.out.println(animals);
}
private static void shift(List<Animal> original, int[] indexes, int newIndex) {
int[] sorted = indexes.clone();
Arrays.sort(sorted);
List<Animal> block = new ArrayList<Animal>();
for (int i = sorted.length - 1; i >= 0; i--) {
block.add(original.get(sorted[i]));
original.remove(i);
}
original.addAll(newIndex, block);
}
Output
[Dog, DogBaby1, DogBaby2, Mokey, MokeyBaby1, MokeyBaby2, MokeyBaby3, Cat, CatBaby1]
I have one Arraylist of String and I have added Some Duplicate Value in that. and i just wanna remove that Duplicate value So how to remove it.
Here Example I got one Idea.
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
System.out.println("List"+list);
for (int i = 1; i < list.size(); i++) {
String a1 = list.get(i);
String a2 = list.get(i-1);
if (a1.equals(a2)) {
list.remove(a1);
}
}
System.out.println("List after short"+list);
But is there any Sufficient way remove that Duplicate form list. with out using For loop ?
And ya i can do it by using HashSet or some other way but using array list only.
would like to have your suggestion for that. thank you for your answer in advance.
You can create a LinkedHashSet from the list. The LinkedHashSet will contain each element only once, and in the same order as the List. Then create a new List from this LinkedHashSet. So effectively, it's a one-liner:
list = new ArrayList<String>(new LinkedHashSet<String>(list))
Any approach that involves List#contains or List#remove will probably decrease the asymptotic running time from O(n) (as in the above example) to O(n^2).
EDIT For the requirement mentioned in the comment: If you want to remove duplicate elements, but consider the Strings as equal ignoring the case, then you could do something like this:
Set<String> toRetain = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
toRetain.addAll(list);
Set<String> set = new LinkedHashSet<String>(list);
set.retainAll(new LinkedHashSet<String>(toRetain));
list = new ArrayList<String>(set);
It will have a running time of O(n*logn), which is still better than many other options. Note that this looks a little bit more complicated than it might have to be: I assumed that the order of the elements in the list may not be changed. If the order of the elements in the list does not matter, you can simply do
Set<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
set.addAll(list);
list = new ArrayList<String>(set);
if you want to use only arraylist then I am worried there is no better way which will create a huge performance benefit. But by only using arraylist i would check before adding into the list like following
void addToList(String s){
if(!yourList.contains(s))
yourList.add(s);
}
In this cases using a Set is suitable.
You can make use of Google Guava utilities, as shown below
list = ImmutableSet.copyOf(list).asList();
This is probably the most efficient way of eliminating the duplicates from the list and interestingly, it preserves the iteration order as well.
UPDATE
But, in case, you don't want to involve Guava then duplicates can be removed as shown below.
ArrayList<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
System.out.println("List"+list);
HashSet hs = new HashSet();
hs.addAll(list);
list.clear();
list.addAll(hs);
But, of course, this will destroys the iteration order of the elements in the ArrayList.
Shishir
Java 8 stream function
You could use the distinct function like above to get the distinct elements of the list,
stringList.stream().distinct();
From the documentation,
Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
Another way, if you do not wish to use the equals method is by using the collect function like this,
stringList.stream()
.collect(Collectors.toCollection(() ->
new TreeSet<String>((p1, p2) -> p1.compareTo(p2))
));
From the documentation,
Performs a mutable reduction operation on the elements of this stream using a Collector.
Hope that helps.
Simple function for removing duplicates from list
private void removeDuplicates(List<?> list)
{
int count = list.size();
for (int i = 0; i < count; i++)
{
for (int j = i + 1; j < count; j++)
{
if (list.get(i).equals(list.get(j)))
{
list.remove(j--);
count--;
}
}
}
}
Example:
Input: [1, 2, 2, 3, 1, 3, 3, 2, 3, 1, 2, 3, 3, 4, 4, 4, 1]
Output: [1, 2, 3, 4]
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
HashSet<String> hs=new HashSet<>(list);
System.out.println("=========With Duplicate Element========");
System.out.println(list);
System.out.println("=========Removed Duplicate Element========");
System.out.println(hs);
I don't think the list = new ArrayList<String>(new LinkedHashSet<String>(list)) is not the best way , since we are using the LinkedHashset(We could use directly LinkedHashset instead of ArrayList),
Solution:
import java.util.ArrayList;
public class Arrays extends ArrayList{
#Override
public boolean add(Object e) {
if(!contains(e)){
return super.add(e);
}else{
return false;
}
}
public static void main(String[] args) {
Arrays element=new Arrays();
element.add(1);
element.add(2);
element.add(2);
element.add(3);
System.out.println(element);
}
}
Output:
[1, 2, 3]
Here I am extending the ArrayList , as I am using the it with some changes by overriding the add method.
public List<Contact> removeDuplicates(List<Contact> list) {
// Set set1 = new LinkedHashSet(list);
Set set = new TreeSet(new Comparator() {
#Override
public int compare(Object o1, Object o2) {
if(((Contact)o1).getId().equalsIgnoreCase(((Contact)2).getId()) ) {
return 0;
}
return 1;
}
});
set.addAll(list);
final List newList = new ArrayList(set);
return newList;
}
This will be the best way
List<String> list = new ArrayList<String>();
list.add("Krishna");
list.add("Krishna");
list.add("Kishan");
list.add("Krishn");
list.add("Aryan");
list.add("Harm");
Set<String> set=new HashSet<>(list);
It is better to use HastSet
1-a) A HashSet holds a set of objects, but in a way that it allows you to easily and quickly determine whether an object is already in the set or not. It does so by internally managing an array and storing the object using an index which is calculated from the hashcode of the object. Take a look here
1-b) HashSet is an unordered collection containing unique elements. It has the standard collection operations Add, Remove, Contains, but since it uses a hash-based implementation, these operation are O(1). (As opposed to List for example, which is O(n) for Contains and Remove.) HashSet also provides standard set operations such as union, intersection, and symmetric difference.Take a look here
2) There are different implementations of Sets. Some make insertion and lookup operations super fast by hashing elements. However that means that the order in which the elements were added is lost. Other implementations preserve the added order at the cost of slower running times.
The HashSet class in C# goes for the first approach, thus not preserving the order of elements. It is much faster than a regular List. Some basic benchmarks showed that HashSet is decently faster when dealing with primary types (int, double, bool, etc.). It is a lot faster when working with class objects. So that point is that HashSet is fast.
The only catch of HashSet is that there is no access by indices. To access elements you can either use an enumerator or use the built-in function to convert the HashSet into a List and iterate through that.Take a look here
Without a loop, No! Since ArrayList is indexed by order rather than by key, you can not found the target element without iterate the whole list.
A good practice of programming is to choose proper data structure to suit your scenario. So if Set suits your scenario the most, the discussion of implementing it with List and trying to find the fastest way of using an improper data structure makes no sense.
public static void main(String[] args) {
#SuppressWarnings("serial")
List<Object> lst = new ArrayList<Object>() {
#Override
public boolean add(Object e) {
if(!contains(e))
return super.add(e);
else
return false;
}
};
lst.add("ABC");
lst.add("ABC");
lst.add("ABCD");
lst.add("ABCD");
lst.add("ABCE");
System.out.println(lst);
}
This is the better way
list = list.stream().distinct().collect(Collectors.toList());
This could be one of the solutions using Java8 Stream API. Hope this helps.
public void removeDuplicates() {
ArrayList<Object> al = new ArrayList<Object>();
al.add("java");
al.add('a');
al.add('b');
al.add('a');
al.add("java");
al.add(10.3);
al.add('c');
al.add(14);
al.add("java");
al.add(12);
System.out.println("Before Remove Duplicate elements:" + al);
for (int i = 0; i < al.size(); i++) {
for (int j = i + 1; j < al.size(); j++) {
if (al.get(i).equals(al.get(j))) {
al.remove(j);
j--;
}
}
}
System.out.println("After Removing duplicate elements:" + al);
}
Before Remove Duplicate elements:
[java, a, b, a, java, 10.3, c, 14, java, 12]
After Removing duplicate elements:
[java, a, b, 10.3, c, 14, 12]
Using java 8:
public static <T> List<T> removeDuplicates(List<T> list) {
return list.stream().collect(Collectors.toSet()).stream().collect(Collectors.toList());
}
In case you just need to remove the duplicates using only ArrayList, no other Collection classes, then:-
//list is the original arraylist containing the duplicates as well
List<String> uniqueList = new ArrayList<String>();
for(int i=0;i<list.size();i++) {
if(!uniqueList.contains(list.get(i)))
uniqueList.add(list.get(i));
}
Hope this helps!
private static void removeDuplicates(List<Integer> list)
{
Collections.sort(list);
int count = list.size();
for (int i = 0; i < count; i++)
{
if(i+1<count && list.get(i)==list.get(i+1)){
list.remove(i);
i--;
count--;
}
}
}
public static List<String> removeDuplicateElements(List<String> array){
List<String> temp = new ArrayList<String>();
List<Integer> count = new ArrayList<Integer>();
for (int i=0; i<array.size()-2; i++){
for (int j=i+1;j<array.size()-1;j++)
{
if (array.get(i).compareTo(array.get(j))==0) {
count.add(i);
int kk = i;
}
}
}
for (int i = count.size()+1;i>0;i--) {
array.remove(i);
}
return array;
}
}
Overview
I have an arrayList that holds multiple int arrays that have two parameters, key and value. (I know there exists a map library, but for this task I wish to use an arrayList).
Imagine my arrayList has the following arrays:
[3, 99][6, 35][8, 9][20, 4][22, 13][34, 10]
As you can see, they are in order by the index, which is done when I first add them to the arrayList.
My problem
if I want to add an array to this arrayList it would appended to the end of the list, whereas I want to add it to the correct position in the list.
I'm fairly new to arrayLists, and as such was wondering if there exists an elegant solution to this problem that I have not come across.
Current thoughts
Currently, my solution would be to iterate over the arrayList, then for every array temporally store the key (array[0]), I would then iterate over again and add my array in the correct position (where it's key is in-between two other keys).
Your idea of iterating through is correct; however there is no need to perform the iteration twice. Finding the right index and inserting the element can be done in one loop. ArrayList has a method add(int, E) that can insert an element into any position in the list. Try this:
//the value you want to insert
int[] toInsert = {someValue, someOtherValue};
//assume theList is the list you're working with
for(int index = 0; index < theList.size() -1; index ++)
{
int key = theList.get(index)[0];
int nextKey = theList.get(index + 1)[0];
//if we've reached the correct location in the list
if (toInsert[0] > key && toInsert[0] < nextKey)
{
//insert the new element right after the last one that was less than it
theList.add(index + 1,toInsert);
}
}
Note that this method assumes that the list is sorted to begin with. If you want to make that a guarantee, look into some of the other answers describing sorting and Comparators.
It may be more elegant to produce a class to hold your two values and ensure that implements Comparable, as shown below:
public class Foo implements Comparable<Foo> {
private int x; // your left value
private int y; // your right value
// Constructor and setters/getters omitted
public int compareTo(Foo o) {
return Integer.compare(x, o.getX());
}
}
Then add and sort as follows:
List<Foo> listOfFoos = new ArrayList<Foo>;
// ...
listOfFoos.add(new Foo(33,55));
Collections.sort(listOfFoos);
That would be the most readable solution. There may be faster options, but only optimise if you can prove this part is a bottleneck.
First Option
If you want to be able to sort your array you should be storing Comparable Objects.
So, you can create a Class that will hold your two value array and implement the Comparable interface.
If you chose this option, after adding the element all you need to do is to call .sort() on your List.
Second Option
You can define Comparator that you can use for sorting. This would be reusable and would allow you to keep your two dimensional arrays. You will also have to sort after each time you add.
Third Option
You could define your Comparator on the fly as shown in this particular question:
Java Comparator class to sort arrays
you can do the following:
import java.util.ArrayList;
public class AddElementToSpecifiedIndexArrayListExample {
public static void main(String[] args) {
//create an ArrayList object
ArrayList arrayList = new ArrayList();
//Add elements to Arraylist
arrayList.add("1");
arrayList.add("2");
arrayList.add("3");
/*
To add an element at the specified index of ArrayList use
void add(int index, Object obj) method.
This method inserts the specified element at the specified index in the
ArrayList.
*/
arrayList.add(1,"INSERTED ELEMENT");
System.out.println("ArrayList contains...");
for(int index=0; index < arrayList.size(); index++)
System.out.println(arrayList.get(index));
}
}
/*
Output would be
ArrayList contains...
1
INSERTED ELEMENT
2
3
*/
There is also a version of add that takes the index at which to add the new item.
int i;
for(i=0; i<arr.size(); i++){
if(arr.get(i)[0] >= newArr[0]){
arr.add(i, newArr);
}
}
if(i == arr.size())
arr.add(i, newArr)
Use a Comparator of int[] along with binarySearch :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Main
{
public static void main(String[] argv)
{
ArrayList<int[]> list = new ArrayList<int[]>();
list.add(new int[] { 3, 99 });
list.add(new int[] { 6, 35 });
list.add(new int[] { 8, 9 });
list.add(new int[] { 20, 4 });
list.add(new int[] { 22, 13 });
list.add(new int[] { 34, 10 });
Compar compar = new Compar();
addElement(list, new int[] { 15, 100 }, compar);
for(int[] t : list)
{
System.out.println(t[0]+" "+t[1]);
}
}
private static void addElement(ArrayList<int[]> list, int[] elem, Compar compar)
{
int index = Collections.binarySearch(list, elem, compar);
if (index >= 0)
{
list.add(index, elem);
return;
}
list.add(-index - 1, elem);
}
static class Compar implements Comparator<int[]>
{
#Override
public int compare(int[] a, int[] b)
{
return a[0] - b[0];
}
}
}
I have a list of strings in my (Android) Java program, and I need to get the index of an object in the list. The problem is, I can only find documentation on how to find the first and last index of an object. What if I have 3 or more of the same object in my list? How can I find every index?
Thanks!
You need to do a brute force search:
static <T> List<Integer> indexesOf(List<T> source, T target)
{
final List<Integer> indexes = new ArrayList<Integer>();
for (int i = 0; i < source.size(); i++) {
if (source.get(i).equals(target)) { indexes.add(i); }
}
return indexes;
}
Note that this is not necessarily the most efficient approach. Depending on the context and the types/sizes of lists, you might need to do some serious optimizations. The point is, if you need every index (and know nothing about the structure of the list contents), then you need to do a deathmarch through every item for at best O(n) cost.
Depending on the type of the underlying list, get(i) may be O(1) (ArrayList) or O(n) (LinkedList), so this COULD blow up to a O(n2) implementation. You could copy to an ArrayList, or you could walk the LinkedList incrementing an index counter manually.
If documentation is not helping me in my logic in this situation i would have gone for a raw approach for Traversing the list in a loop and saving the index where i found a match
ArrayList<String> obj = new ArrayList<String>();
obj.add("Test Data"): // fill the list with your data
String dataToFind = "Hello";
ArrayList<Integer> intArray = new ArrayList<Integer>();
for(int i = 0 ; i<obj.size() ; i++)
{
if(obj.get(i).equals(dataToFind)) intArray.add(i);
}
now intArray would have contained all the index of matched element in the list
An alternative brute force approach that will also find all null indexes:
static List<Integer> indexesOf(List<?> list, Object target) {
final List<Integer> indexes = new ArrayList<Integer>();
int offset = 0;
for (int i = list.indexOf(target); i != -1; i = list.indexOf(target)) {
indexes.add(i + offset);
list = list.subList(i + 1, list.size());
offset += i + 1;
}
return indexes;
}