I started using the Android SparseArray recently in place of in place of ArrayList for small numbers of items. I am wondering why it does not contain a toArray() method like a normal ArrayList? It contains a private objects array for values but no way of returning them. It seems to me that this would be a useful method to have as ArrayList to array conversions are common occurrences in Android. I am assuming that because of the way hashing works it would return an array with empty slots?
My second question is, what would be the most efficient way to convert a SparseArray to a normal Object array?
To answer the title of your question, there is no method for this because the SparseArray is not an array, it is in fact an optimization of a HashMap, binding arbitrary integers to arbitrary values. The optimization lies in the fact that it uses no boxing/unboxing where a HashMap would.
Then the second part, how you should convert it to an array, I would recommend determining the largest array index using size() and keyAt(index), and then allocating an array of the appropriate size, and finally copying all values using the get(index, default) method with a sensible default.
theres no such method to do that, but you can convert the SparseArray iterating :
public static <C> List<C> ConvertToList(SparseArray<C> sparseArray) {
if (sparseArray == null) return null;
List<C> arrayList = new ArrayList<C>(sparseArray.size());
for (int i = 0; i < sparseArray.size(); i++)
arrayList.add(sparseArray.valueAt(i));
return arrayList;
}
Kotlin version:
private inline fun <reified VALUE> SparseArray<VALUE>.toArrayOrNull(): Array<VALUE>? {
return if (isNotEmpty()) {
Array<VALUE>(size()) { index -> this[index] }
} else {
null
}
}
Related
I was using Arrays.sort() function to sort 2d array (int[][] array). Since I want to sort it base on the first element. For example, {{2,3},{1,4}} base on 1st element the array will be {{1,4},{2,3}}. So I override the compare function.
Arrays.sort(arr, new Comparator<int[]>() {
#Override
public int compare(int[] o1, int[] o2){
if(o1[0] < o2[0]){
return -1;
} else if (o1[0] > o2[0]) {
return 1;
} else {
return 0;
}
}
})
I know this sort work. But I don't understand how this compare work.
I was thinking the
new Comparator<int[]>
should be
new Comparator<int[][]>
since this is 2d array. and inside of compare function should be compare
o1[0][0] and o2[0][0]
Can anyone help me understand it?
Also this is using Arrays.sort, can I use Collections.sort? what is different between it?
Thanks
Remember that a "2D array" doesn't actually exist in Java, so what you're really dealing with is "an array of int[]" (there's nothing inherently preventing each of those int[] from being a different length).
So: when you sort, you're comparing individual elements of that "array of int[]" with each other, and because each element is an int[], your Comparator is for int[], too.
You are passing the array in the sort method and giving it a comparator. Arrays.sort will use iterator to pass into compare method. So compare method is checking element at arr[0].compare(arr[1]) sorts these 2 and goes to next iterator. same concept applies using 2d array. You are just passing 2 arrays and telling compare who should be placed where.
I am Passing an Array into a for loop with an if statment, I am want to have all the elements that evaluate true be added to a new array. How Do I do This?
Supposing you have an object array, and you want to create a possibly smaller array containing the elements that satisfy some predicate, you are faced with the problem of knowing how big to make the new array. You can determine that only by testing each starting element against the predicate, which you would normally prefer to avoid doing twice. One way to approach the problem would be to use a List to temporarily hold the elements you want to collect:
MyElementType[] myArray = { /* ... */ };
MyElementType[] result;
List<MyElementType> temp = new ArrayList<MyElementType>();
for (MyElementType element : myArray) {
if (passesMyTest(element)) {
temp.add(element);
}
}
result = temp.toArray(new MyElementType[0]);
Of course, it's usually easier to work directly with Lists instead of with arrays, but sometimes you don't have that luxury.
I have a list and a Object as bellow
List<MyObj> myList;
public class MyObjextends
{
String parameter1;
public String getParameter1()
{
return parameter1;
}
}
I need an efficient way to get the count of myList based on the value of parameter1 in the object without going through a for loop as bellow
int count = 0;
for( MyObj obj: myList)
{
if( obj.getParameter1().equals( "Somet_Text") )
{
count++;
}
}
Can someone please tell me how to do this?
Use a Map from parameter1 to List of MyObj and then you can use the size of map.get("Some_Text")
You could wrap the list up in a class which also has a HashMap<String, List<MyObj>>. Only allow access to the list via methods which also control the hash map. Whenever an item is added to the list, it should also be added to the hash map.
if stay with List structure, you have to do it with loop. if you don't do it, the api you used will do it any way.
If this is the main problem you want to solve, you can consider to use MultiMap Structure. Like guava's ListMultimap<String, MyObj>.
In fact it is something like map<String, List<MyObj>>
I dont understand why you would not use a for loop to iterate List, Even if efficiency is a consideration, it would not matter at all practically. But even then if you have something against for, use the iterator for list
ListIterator<MyObj> it=myList.listIterator();
int count = 0;
while(it.hasNext()){
if( it.next().getParameter1().equals( "Somet_Text") )
{
count++;
}
}
Also looking at the source for ListIterator.next() , it does not use for loop too, just if it makes any difference
public E More ...next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
But note that it uses if statement and increments cursor to traverse the list, which again would be something like a for loop.
You don't have a real reason to not wanting search in a ordered array as interface List is with a loop. The big O notation of this loop would be O(N) which is exactly what is pretended to be.
If you have to process data from a huge array of inputs, I would recommend pre-process the information by discarding the objects with the values you don't want and create the array with the values that you really need.
The Map solutions commented won't solve your problem neither, as one rule of construction is that no repeated values are allowed, which is exactly what you want to measure.
I'm stuck trying to get something to work in an assignment. I have a HashMap<Integer, ArrayList<Object>> called sharedLocks and I want to check whether a certain value can be found in any ArrayList in the HashMap.
The following code obviously wouldn't work because Object[] can't be cast to ArrayList[], but it is a demonstration of the general functionality that I want.
ArrayList[] values = (ArrayList[]) sharedLocks.values().toArray();
boolean valueExists = false;
for (int i = 0; i < values.length; i++) {
if (values[i].contains(accessedObject)) {
valueExists = true;
}
}
Is there a way for me to check every ArrayList in the HashMap for a certain value? I'm not sure how to use the values method for HashMaps in this case.
Any help would be much appreciated.
HashMap.values() returns a Collection. You can iterate through the collection without having to convert it to an array (or list).
for (ArrayList<Object> value : sharedLocks.values()) {
...
}
A HashMap is a bit special, in that it doesn't really have an index to go by at all...
What you want to do, is turn the HashMap into a collection first, and then iterate through the collection with an iterator.
Whenever you get hold of an ArrayList in the HashMap, you cycle through every element in the arrayList, and then you jump out if you find it :)
Use the toArray method which takes an array as an argument.
This uses the array you specify to fill the data, and maintains the typing so you don't need to typecast. Additionally, you should keep the generic <Object> in the definition.
ArrayList<Object>[] values =
sharedLocks.values().toArray(new ArrayList<Object>[sharedLocks.size()]);
One more thing to consider is if multiple threads can modify this HashMap. In this case, you will want to synchronize this line of code to the HashMap and make sure all modifications are also synchronized. This will make sure that other threads won't modify the contents between the .size() call and the .toArray() call, which is possible.
You dont need arrays:
boolean valueExists = false;
for (ArrayList<Object> value : sharedLocks.values()) {
if (value.contains(accessedObject)) {
valueExists = true;
break;
}
}
Why not just iterate through all the values in the map:
for (ArrayList<Object> list : sharedLocks) {
if (list.contains(accessedObject)) {
// ...
}
}
heres a link to an example of iterating though a hash map. Use this to pull out each arraylist and in turn extend this to then search each element of the array list for the given entry.
http://www.java-examples.com/iterate-through-values-java-hashmap-example
you will need to use a nested foreach loop.
foreach(every element in the hashmap) {
foreach(every element in arraylist) {
// do comparision
}
}
you might just get away with a foreach loop and a keyExists() call or something within it. I cannot recall the API off the top of my head.
This is what I have right now:
public ArrayList subList(int fromIndex, int toIndex){
ArrayList a = new ArrayList();
for (int i=fromIndex;i<toIndex;i++) {
a.add(stuff[i]); //stuff is a array of strings
}
return list;
}
But is it possible to return the sublist without creating a new array? I am restrict from using any methods from the Array/ArrayList class.
If you want have the same behaviour as the Java subList method you need to retain a pointer to the original list and use an offset and length to index into the original list.
Heres a start showing the implementation of the get method.
public class SubList extends AbstractList {
private final List original;
private final int from;
private final int to;
public SubList(List original, int from, int to) {
this.original = original;
this.from = from;
this.to = to;
}
public Object get(int i) {
if (i < 0 || i > to - from) {
throw new IllegalArguementException();
}
return original.get(from + i);
}
}
public static List subList(List original, int from, int to) {
return new SubList(original, from, to);
}
To avoid creating a new list for storage, you would have to pass in a reference to the original list, keep the sublist, and then delete the remaining items from from the list, but this would leave the list missing those other items.
If that isn't your goal you will have to create a new list at some point to hold the sublist.
I assume you have to return the standard ArrayList, and not your own version of ArrayList, and I assume that 'stuff' is an array, not a list.
First off, get bonus points for making the ArrayList have the initial size of the array (toIndex - fromIndex). For more bonus points, make sure that the to and from indecies actually exist in 'stuff' otherwise you get a nice crash.
ArrayList uses an internal array for its storage and you can't change that so you have no choice but to create a copy.
EDIT
You could make things interested and much more complex but it'll impress someone... Do it by creating your own ArrayList class implementing List. Get it to use that original array. Pretty unstable since if that array is modified somewhere else externally, you're in trouble, but it could be fun.
There's three sensible things you could return. An array, a List, or an Iterator. If my assumption that you're supposed to re-implement subList was correct, then there's no way around creating the new ArrayList.
A sublist is "a new list", so you'll have to create something to represent the sublist of the array. This can either be a new array or a list. You chose an ArrayList which looks good to me. You're not creating a new array (directly), so I don't actually get that point of your question. (If you want to avoid creating a new array indirectly through ArrayList, choose another List implementation, LinkedListfor example)
If you're looking for slight improvements:
Consider passing the source array as a method parameter. Now stuff[] is a static field.
Consider initializing the new ArrayList with the size of the sublist (toList-fromList+1)
Consider using generics (only if you already now this concept). So the return type would be ArrayList<String>