I want to keep the indices of the items in a Java List fixed.
Example code:
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<Double> a = new ArrayList<Double>();
a.add(12.3);
a.add(15.3);
a.add(17.3);
a.remove(1);
System.out.println(a.get(1));
}
}
This will output 17.3. The problem is that 17.3 was on index 2 and now it's on index 1!
Is there any way to preserve the indices of other elements when removing an element? Or is there another class more suitable for this purpose?
Note: I don't want a fixed size Collection.
You might want to use java.util.SortedMap with int keys:
import java.util.*;
public class Test {
public static void main(String[] args)
{
SortedMap<Integer, Double> a = new TreeMap<Integer, Double>();
a.put(0, 12.3);
a.put(1, 15.3);
a.put(2, 17.3);
System.out.println(a.get(1)); // prints 15.3
System.out.println(a.get(2)); // prints 17.3
a.remove(1);
System.out.println(a.get(1)); // prints null
System.out.println(a.get(2)); // prints 17.3
}
}
SortedMap is a variable-size Collection
It stores values mapped to an ordered set of keys (similar to List's indices)
No implementation of java.util.List#remove(int) may preserve the indices since the specification reads:
Removes the element at the specified position in this list (optional operation). Shifts any subsequent elements to the left (subtracts one from their indices). Returns the element that was removed from the list.
Instead of calling a.remove(1) you could do a.set(1, null). This will keep all elements in the same place while still "removing" the value at index one.
If the relationship should be always the same between the index and value then use a java.util.Map.
Instead of removing the element with the call to remove set the element to null:
i.e:
import java.util.ArrayList;
public class Test
{
public static void main(String[] args)
{
ArrayList<Double> a = new ArrayList<Double>();
a.add(12.3);
a.add(15.3);
a.add(17.3);
a.set(1, null);
System.out.println(a.get(1));
}
}
You could use a HashMap<Integer, Double>. You could add items using
myMap.put(currentMaximumIndex++, myDoubleValue);
This way, indices would be unique, if you need sparse storage you'd be reasonably okay, and removing a value wouldn't hurt existing ones.
Addition to the above answer its also suggested you should use LinkedHashMap<Integer,Double>, instead of a regular Hashmap
It will preserve the order in which you insert the element.
Related
I remember this data structure which works based on indexes, as in an array or a list. However, if you put several values under the same index, that index turns into a linked list. Thus, upon adding new elements to that same index, the linked list would grow automatically.
I assume it is not just a 2D array. Also I heard it's possible to create an array of linked lists, but I still doubt that it is what I'm interested in.
Also, I assume that this is like some data structure from Java Collection because I remember seeing some code in Java containing this structure, but forgot its name.
Can some come up with some clues what may it be?
Or whether such data structure even exist?
Thanks
You can create your own data structure to implement the exact behavior you want.
One way to do this, is to use a HashMap of Integer as key and LinkedList as value.
Here is an example:
public class IndexMap {
Map<Integer, LinkedList<Integer>> map;
public IndexMap(){
map = new HashMap<Integer, LinkedList<Integer>>();
}
public void add(int index, int value) {
if(map.containsKey(index)) {
map.get(index).add(value);
}else {
LinkedList<Integer> list = new LinkedList<>();
list.add(value);
map.put(index, list);
}
}
public void remove(int index, int value) {
if(map.containsKey(index))
map.get(index).remove(new Integer(value));
}
#Override
public String toString() {
return map.toString();
}
public static void main(String[] args) {
IndexMap map = new IndexMap();
map.add(0,0);
map.add(0,1);
map.add(1,0);
map.add(2,0);
map.add(2,1);
System.out.println(map);
map.remove(0,1);
System.out.println(map);
}
}
Sample demo:
{0=[0, 1], 1=[0], 2=[0, 1]}
{0=[0], 1=[0], 2=[0, 1]}
You can alter the methods or add new ones to implement more functionalities.
You are probably thinking of a multimap. While there is no implementation in base java, there is one in google guava.
Here are introductions on how to use it in your build.
I'm using a set to get a list of duplicate items from an ArrayList (which is populated from a database)
void getDuplicateHashTest() {
List<BroadcastItem> allDataStoreItems = itemsDAO.getAllItems();
Set<BroadcastItem> setOfAllData = new HashSet<>(allDataStoreItems);
List<BroadcastItem> diff = new ArrayList<>(setOfAllData);
allDataStoreItems.removeAll(diff);
}
So at the last line, all the items which are not duplicates should be removed from the list of all items.
The problem is when I print allDataStoreItems.size() I get 0
The set and the sublist print the correct number of items.
What am I doing wrong?
List#removeAll removes all occurrences of the given elements, not just one of each (in contrast to List#remove which only removes the first occurrence). So setOfAllData contains one copy of each element in your list, and then you remove all occurrences of each of those elements, meaning you'll always end up with an empty list.
To know how to fix this I'd need to know more about what you want the result to be. Do you want one copy of each element removed? If so, you could do that with:
List<BroadcastItem> allDataStoreItems = itemsDAO.getAllItems();
Set<BroadcastItem> setOfAllData = new HashSet<>(allDataStoreItems);
setOfAllData.forEach(allDataStoreItems::remove);
Its simple if you want to store only duplicates find the below code.
Set<BroadcastItem> duplicates = new HashSet<>;
Set<BroadcastItem> allItems=new HashSet<>
for(BroadcastItem b:allDataStoreItems){
boolean x=allItems.add(b);
if(x==false){
duplicates.add(b);
}
}
As already pointed out in the answer by jacobm : The Collection#removeAll method will remove all occurrences of a particular element. But the alternative of creating a list and calling remove repeatedly is not really a good solution: On a List, the remove call will usually have O(n) complexity, so figuring out the duplicates like this will have quadratic complexity.
A better solution is the one that was already mentioned by shamsher Khan in his answer (+1!) : You can iterate over the list, and keep track of the elements that have already seen, using a Set.
This solution has a complexity of O(n).
It's not clear whether you want the list or the set of all duplicates. For example, when the input is [1, 2,2,2, 3], should the result be [2,2] or just [2]? However, you can simply compute the list of duplicates, and make its elements unique in a second step, if necessary.
Here is an example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class FindDuplicatesInList
{
public static void main(String[] args)
{
List<Integer> list = Arrays.asList(0,1,1,1,2,3,3,4,5,6,7,7,7,8);
List<Integer> duplicates = computeDuplicates(list);
// Prints [1, 1, 3, 7, 7]
System.out.println(duplicates);
// Prints [1, 3, 7]
System.out.println(makeUnique(duplicates));
}
private static <T> List<T> makeUnique(List<? extends T> list)
{
return new ArrayList<T>(new LinkedHashSet<T>(list));
}
private static <T> List<T> computeDuplicates(List<? extends T> list)
{
Set<T> set = new HashSet<T>();
List<T> duplicates = new ArrayList<T>();
for (T element : list)
{
boolean wasNew = set.add(element);
if (!wasNew)
{
duplicates.add(element);
}
}
return duplicates;
}
}
I'm writing a simple program to recursively find all subsets of some larger set. I've got it working, but I wanted to order all of the sets in order by size.
I posted my working code below.
import java.util.*;
public class AllSubsets {
public static void main(String[] args) {
// Change contents of this array to easily change contents of set.
Integer[] setContents = {3, 6, 8, 9, 10, 22};
// create initial unused set by dumping all of the aray into a set.
Set<Integer> unused = new HashSet<Integer>(Arrays.asList(setContents));
// create initial empty set for used set.
Set<Integer> used = new HashSet<Integer>();
// create output set of sets.
Set<Set<Integer>> allSets = new HashSet<Set<Integer>>();
allSets.add(used);
// find all sets recursively
findAllSets(used, unused, allSets);
// print out results
System.out.println(allSets);
}
public static void findAllSets(Set<Integer> used, Set<Integer> unused,
Set<Set<Integer>> allSets) {
if (unused != null) {
Set<Integer> copyOfUnused = new HashSet<Integer>(unused);
for (Integer val : copyOfUnused) {
unused.remove(val);
used.add(val);
allSets.add(new HashSet<Integer>(used));
findAllSets(used, unused, allSets);
used.remove(val);
unused.add(val);
}
}
}
}
I was wondering what the best way would be to order these sets by size. I tried to create a TreeSet which holds multiple HashSet objects with it's comparator method overwritten. This ended up compiling but didn't store the values correctly. The code for this I wrote is very similar to the code above, so I will write out the main difference below:
Set<Set<Integer>> allSets =
new TreeSet<Set<Integer>>(new Comparator<Set<Integer>>() {
public int compare(Set<Integer> a, Set<Integer> b) {
return a.size() - b.size();
}
});
In this version of the code, it compiles but the objects are not storing correctly. The proper sets are being computed and added to "allSets" in the recursive method (tested using println) but it only ever holds one set at a time. I have a feeling it's mostly because I overwrote the Comparator for Set but I am using HashSets. Is there a better way to organize my sets or maybe just a small bug in my code?
Thanks!!
TreeSet<Set<Integer>> will only store one Set element with a given size, because it considers two different sets with the same size to be "equal": it takes a.compareTo(b) == 0 to mean a == b.
If you want to get all of the sets and then print them in order of size, gather all of the sets in a regular (Hash)Set, and then sort the entries:
List<Set<Integer>> listOfSets = new ArrayList<>(allSets);
Collections.sort(listOfSets, <your comparator above>);
System.out.println(listOfSets).
Guys i wanna ask about the best way to iterate collection classes ??
private ArrayList<String> no = new ArrayList<String>();
private ArrayList<String> code = new ArrayList<String>();
private ArrayList<String> name = new ArrayList<String>();
private ArrayList<String> colour = new ArrayList<String>();
private ArrayList<String> size = new ArrayList<String>();
// method for finding specific value inside ArrayList, if match then delete that element
void deleteSomeRows(Collection<String> column, String valueToDelete) {
Iterator <String> iterator = column.iterator();
do{
if (iterator.next()==valueToDelete){
iterator.remove();
}
}while(iterator.hasNext());
}
deleteSomeRows(no, "value" );
deleteSomeRows(code, "value" );
deleteSomeRows(name , "value");
deleteSomeRows(colour ,"value" );
deleteSomeRows(size , "value");
THE PROBLEM WITH CODES ABOVE IS THAT IT TAKES AMOUNT OF TIME JUST TO ITERATE EACH OF THOSE CLASSES ? ANY SOLUTION TO MAKE IT FASTER ? pls help if u care :D..
You could simplify your code:
while column.contains(valueToDelete)
{
column.remove(valueToDelete);
}
You're not going to be able to speed up your ArrayList iteration, especially if your list is not sorted. You're stuck at O(n) for this problem. If you sorted it and inserted logic to binary search for the item to remove until it is no longer found, you could speed up access.
This next suggestion isn't directly related to the time it takes, but it will cause you problems.
You should never compare String objects for equality using the == operator. This will cause a comparison of their pointer values.
Use this instead:
if (iterator.next().equals(valueToDelete))
EDIT: The problem here is not the iteration. The problem is removing the elements from the ArrayList. When you remove the first element from an ArrayList, then all subsequent elements have to be shifted one position to the left. So in the worst case, your current approach will have quadratic complexity.
It's difficult to avoid this in general. But in this case, the best tradeoff between simplicity and performance can probably be achieved like this: Instead of removing the elements from the original list, you create a new list which only contains the elements that are not equal to the "valueToDelete".
This could, for example, look like this:
import java.util.ArrayList;
import java.util.List;
public class QuickListRemove
{
public static void main(String[] args)
{
List<String> size = new ArrayList<String>();
size = deleteAll(size, "value");
}
private static <T> List<T> deleteAll(List<T> list, T valueToDelete)
{
List<T> result = new ArrayList<T>(list.size());
for (T value : list)
{
if (!value.equals(valueToDelete))
{
result.add(value);
}
}
return result;
}
}
If you want to modify the collection while iterating them then you should use Iterators, otherwise you can use the for-each loop.
For -each :
// T is the type f elements stored in myList
for(T val : myList)
{
// do something
}
Try putting a break after you find the element to delete.
Unlike HashMap, order matters in LinkedHashMap. And the order here is insertion order.
Let say I have a LinkedHashMap like the following (ordered from the top to bottom, left part is key, right part is value):
1:"One"
2:"Two"
3:"Three"
4:"Four"
Then I have a list of keys, which contains, let's say, (3,1).
What I want to do is to loop through the LinkedHashMap in order and pick out the entries whose key is in the list.
So the result I want to have is (1 is still before 3 because that's the order before filtering):
1:"One"
3:"Three"
Here is my code:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SelectCertainEntriesFromLinkedHashMap {
public static void main(String args[]) {
Map<Integer,String> linkedHashMap = new LinkedHashMap<Integer,String>();
linkedHashMap.put(1, "One");
linkedHashMap.put(2, "Twe");
linkedHashMap.put(3, "Three");
linkedHashMap.put(4, "Four");
List<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(1);
Map<Integer,String> selectedlinkedHashMap = new LinkedHashMap<Integer,String>();
//will this iterator iterate the keys in the order of the map (1, 2, 3, 4)? Or just random order?
Iterator<Integer> itr = linkedHashMap.keySet().iterator();
while(itr.hasNext()) {
Integer key = itr.next();
if (list.contains(key)) {
selectedlinkedHashMap.put(key, linkedHashMap.get(key));
System.out.println(key + ":" + linkedHashMap.get(key));
}
}
}
}
The above code return the result I like. But I am not sure if it is guaranteed.
1:"One"
3:"Three"
The question is:
Iterator itr = linkedHashMap.keySet().iterator();
The above line will get a iterator from a set and set is not ordered. So will this cause the keys in random order? if yes, I can't keep the original order (not guaranteed) of my map after filtering....
Could anybody help me with this?
The iterator returned from keySet().iterator() should return an ordered Set. Documentation from the Map API:
The Map interface provides three collection views, which allow a map's contents to be
viewed as a set of keys, collection of values, or set of key-value mappings. The order of
a map is defined as the order in which the iterators on the map's collection views return
their elements. Some map implementations, like the TreeMap class, make specific guarantees
as to their order; others, like the HashMap class, do not.
So in the LinkedHashMap case I interpret this as saying the iterator will return an ordered Set. It's true the LinkedHashMap API is not explicit about this but you could just try it out and observe your output.
When you call keySet(), that creates a view of the keys based on the underlying data. Admittedly it's not very clearly documented, but as it is just a view, it would be incredibly weird for that view to be iterated in a different order.
You could check the implementation of course, but I'm sure it's fine.
have you tried it? I'm not sure it returns them in the same order as they were inserted, but in this particular case, you could create a TreeSet with the KeySet obtained and since they are integers its gonna be naturally order. 1 and then 3.
kinda like:
Set<Integer> set = new TreeSet<Integer>(linkedHashMap.keySet());