I am trying to write a while loop that will continue to iterate until the nodes list does not have a certain key in a it's map. My code looks like this:
List<Map<Integer, Integer>> nodes = new LinkedList<Map<Integer, Integer>>();
List<Integer> parent = new LinkedList<Integer>();
.
.
.
while (parent != null) {
int vertex = parent.remove(0);
while(//The problem )
}
}
I will be pulling the integer from parent and placing it into vertex and will be using vertex to find the key in the nodes. What would the call look like to find the integer in nodes?
This might help
for(int vertex: parent) {
for(Map<Integer, Integer) entry : nodes) {
if(entry.contains(vertex) {
//the map entry has the key, write your logic and return
return entry
}
}
}
I'm not exactly sure if that's what you want but it might.
List<Map<Integer, Integer>> nodes = new LinkedList<Map<Integer, Integer>>();
LinkedList<Integer> parent = new LinkedList<Integer>();
// ^ or Queue to use .poll() which removes the first item
Integer parentItem;
while ((parentItem = parent.poll()) != null) {
// check if that item is somewhere in the maps
boolean inMaps = false;
for(Map<Integer, Integer> map : nodes) {
if (map.containsKey(parentItem)) {
inMaps = true;
break;
}
}
// if it is not do something special, maybe "return" or "break;"
if (!inMaps) {
// do something.
}
}
Related
I have an ArrayList of objects that have a version number as a field. I want to do some work on that ArrayList, but I only want the most recent version of the object. I was thinking of coding as such:
ArrayList<ObjectVO> ObjectList = getObjectList();
for(ObjectVO myVO : ObjectList) {
Iterator<ObjectVO> iter = ObjectList.iterator();
while(iter.hasNext()) {
ObjectVO checkVO = iter.next();
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
iter.remove();
}
}
}
}
Is this valid? I don't know if the fact that we are in a for loop originally would break the mutability of the ArrayList at runtime.
No, this won't work. iter.remove() will cause the out for loop to fail with ConcurrentModificationException.
Instead of doing this, you can do this with indexed for loops, and a BitSet to keep track of things you want to remove:
BitSet toRemove = new BitSet();
for (int m = 0; m < ObjectList.size(); ++m) {
if (toRemove.get(m)) continue;
ObjectVO myVO = ObjectList.get(m);
for (int c = 0; c < ObjectList.size(); ++c) {
if (toRemove.get(c)) continue;
ObjectVO checkVO = ObjectList.get(c);
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
toRemove.set(c);
}
}
}
}
This is basically your code, but it doesn't do the removal yet. Then you can sweep through the list after and remove them:
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (!toRemove.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
The point of using a BitSet like this is that removal from an ArrayList is inefficient if you are removing from anywhere other than the end, because it requires all of the elements "to the right" of the element you remove to be shuffled along by one position. The loop with the set/get and clear allows you to only move each of the retained elements once.
You can do a bit better than the quadratic loop, though, if you group the list elements by things with the same ID: then you don't need to keep on checking the entire list:
BitSet toKeep = new BitSet();
IntStream.range(0, ObjectList.size())
.mapToObj(a -> a)
.collect(
groupingBy(a -> ObjectList.get(a).getID(),
maxBy(comparingInt(a -> ObjectList.get(a).getVersion()))))
.values()
.forEach(a -> toKeep.set(a));
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (toKeep.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
Assuming you have the memory, rather than do an O(N^2) operation, you could do this more efficiently (O(N)) by using a Map to track the newest Version for each Id. One pass tracks the newest version for each Id, and the second removes elements which are not the latest.
Map<Integer, Thing> newestById = new HashMap<>();
for (Thing thing : list) {
newestById.merge(thing.id, thing, (a,b) -> a.version > b.version ? a : b);
}
list.removeIf(thing -> thing != newestById.get(thing.id)); }
Depending on your use case, you might even be able to store your data in a Map instead of a List, and check if the version is the latest before adding it to the Map.
As the other answers have discussed this won't work. You have three options as I see them, trading memory for CPU cycles/flexibility. I've used Integer instead of ObjectVO in my examples, but it'll be trivial to swap them.
Option 1 - moderate memory, single-pass of the array
Track the highest ID you've seen and populate an ArrayList with new items as they meet the criteria. When you encounter a new higher ID, throw away the ArrayList and create a new one:
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
ArrayList<Integer> allObjectsMatchingId = new ArrayList<>();
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
allObjectsMatchingId = new ArrayList<>();
} else if(currentObject == bestId) {
allObjectsMatchingId.add(currentObject);
}
}
return allObjectsMatchingId;
Option 2 - more expensive memory, single-pass of the array, most flexible.
For each ID you see, create an ArrayList and store it against a map. This allows you to easily change the criteria about what ID you want to keep.
ArrayList<Integer> objectList = getObjectList();
Map<Integer, ArrayList<Integer>> objectsById = new HashMap<>();
for(Integer currentObject : objectList) {
ArrayList<Integer> listForId = objectsById.get(currentObject);
if(listForId == null) {
listForId = new ArrayList<Integer>();
}
listForId.add(currentObject);
objectsById.put(currentObject, listForId);
}
Integer bestId = -1;
for(Integer i : objectsById.keySet()) {
if(i > bestId) {
bestId = i;
}
}
return objectsById.get(bestId);
Option 3 - no additional memory aside from id, two-passes of the array.
Search through the ArrayList for the highest ID, then filter the array to only elements that pass that filter.
This is the closest to your current implementation, the difference being that you do them in separate steps. This reduces complexity from O(N^2) to O(N), and is valid as you aren't modifying the ArrayList while iterating it. You could use a Stream here to filter instead of an iterator if you're Java 8 compatible. See Java: Efficient ArrayList filtering?
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
}
}
Iterator<Integer> iter = objectList.iterator();
while(iter.hasNext()) {
if(iter.next() != bestId) {
iter.remove();
}
}
Why not use Java Streams to solve this:
Collection<ObjectVO> result = objectList.stream()
.collect(Collectors.toMap(ObjectVO::getID, Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(ObjectVO::getVersion))))
.values();
This creates a map which contains the max version for each id. Then you can just use Map.values() to get the object list.
If you need a List or an ArrayList you can just use new ArrayList<>(result).
I have a HashMap<GC, List<RR>> with sample data like:
key values
gc1 - rr1
- rr2
- rr3
gc2 - rr4
- rr5
gc3 - rr6
And I need to create all possible combinations of RR from different GC like:
Combination1: rr1, rr4, rr6
Combination2: rr1, rr5, rr6
Combination3: rr2, rr4, rr6
Combination4: rr2, rr5, rr6
Combination5: rr3, rr4, rr6
Combination6: rr3, rr5, rr6
What I've tried so far is, as #Sanket Makani suggests, to turn my HashMap<GC, List<RR>> into a List<List<RR>>, and then iterate through all the elements like:
List<List<RR>> inputList = new ArrayList<List<RR>>();
for (Map.Entry<GC, List<RR>> rrList : Map.entrySet()) {
inputList.add(rrList.getValue());
}
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
for (List<RR> rrList : inputList) {
List<RR> rrList1 = new ArrayList<RR>();
for (RR rr : rrList) {
rrList1.add(rr);
}
combinationsList.add(rrList1);
}
This is not working for me, as it groups all the RR inside one GC like:
Combination1: rr1, rr2, rr3
Combination2: rr4, rr5
Combination3: rr6
So my quesiton is, how can I adapt my code to obtain the expected result?
PS: I'm working with Java6 unfortunately, so no lambdas/streams allowed.
PS2: I've seen similar questions, but can't find and exact example of what I'm looking for.
EDIT:
This is my final implementation with #nandsito's answer:
//this method groups RRs by GC key with a given list
HashMap<GC, List<RR>> GCRRHashMap = groupRRsByGC(list);
List<Map.Entry<GC, List<RR>>> mapEntryList = new ArrayList<Map.Entry<GC, List<RR>>>(GCRRHashMap.entrySet());
List<List<RR>> combinationsList = new ArrayList<List<RR>>();
List<RR> combinations = new ArrayList<RR>();
generateCombinations(mapEntryList, combinations, combinationsList);
private void generateCombinations(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations, List<List<RR>> combinationsList) {
if (mapEntryList.isEmpty()) {
combinationsList.add(new ArrayList<RoomStay>(combinations));
return;
}
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
generateCombinations(mapEntryList, combinations, combinationsList);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
Here's a recursive solution:
public static void main(String[] args) {
// your data map
Map<GC, List<RR>> map;
// the map entry set as list, which will help
// combining the elements
//
// note this is a modifiable list
List<Map.Entry<GC, List<RR>>> mapEntryList =
new ArrayList<Map.Entry<GC, List<RR>>>(map.entrySet());
// the combinations list, which will store
// the desired results
List<RR> combinations = new ArrayList<RR>();
doRecursion(mapEntryList, combinations);
}
private static void doRecursion(
List<Map.Entry<GC, List<RR>>> mapEntryList,
List<RR> combinations) {
// end of recursion
if (mapEntryList.isEmpty()) {
// do what you wish
//
// here i print each element of the combination
for (RR rr : combinations) {
System.out.println(rr);
}
System.out.println();
return;
}
// remove one GC from the entry list,
// then for each RR from the taken GC
// put RR in the combinations list,
// call recursion
// the remove RR from the combinations list
// end for each
// then put GC back into its list
Map.Entry<GC, List<RR>> entry = mapEntryList.remove(0);
List<RR> entryValue = new ArrayList<RR>(entry.getValue());
while (!entryValue.isEmpty()) {
RR rr = entryValue.remove(0);
combinations.add(rr);
doRecursion(mapEntryList, combinations);
combinations.remove(combinations.size() - 1);
}
mapEntryList.add(0, entry);
}
All you really need to do is work through an incrementing index list:
0,0,0
0,1,0
1,0,0
1,1,0
2,0,0
... etc.
It should be obvious how to translate each of those rows into to values from your data structure. e.g. 0,0,0 maps to rr1, rr4, rr6. This will involve converting the map into a list so that indexes are consistent.
It's very much like a normal base-b count where you increment the rightmost column and if it overflows, set to zero and increment the next one. The only difference is that each column overflows at a different number.
So:
boolean increment(int[] indexes) {
int column = 0;
while(true) {
indexes[column]++;
if(indexes[column] < numberOfRRsInColumn(column)) {
return true; // finished
}
indexes[column]=0;
column++;
if(column = indexes.length) {
return false; // can't increment, no more.
}
}
}
This implementation uses indexes[0] as the "rightmost" column. I've glossed over numberOfRRsInColumn(), but it should be pretty obvious how to do it.
Then:
int[] indexes = new int[mapsize];
do {
output(translate(map, indexes));
} while (increment(indexes));
I want to remove all entries from a LinkedHashMap that were added after an entry with a given key.
My first try was:
LinkedHashMap<String, SomeObject> var = new LinkedHashMap<String, SomeObject>();
public void removeEntriesAfter(String key) {
boolean deleteEntries = false;
for (String currentKey : var.keySet()) {
if(deleteEntries) {
var.remove(currentKey);
} else {
if(key.equalsIgnoreCase(currentKey)) {
// Do not remove the current entry
deleteEntries = true;
}
}
}
}
But then I received a java.util.ConcurrentModificationException.
My second idea was to first determine the keys, an remove them afterwards.
public void removeEntriesAfter(String key) {
boolean deleteEntries = false;
List<String> listOfEntriesToBeRemoved = new ArrayList<String>();
// Determine entries to be deleted
for (String currentKey : var.keySet()) {
if(deleteEntries) {
listOfEntriesToBeRemoved.add(currentKey);
} else {
if(key.equalsIgnoreCase(currentKey)) {
// Do not remove the current entry
deleteEntries = true;
}
}
}
// Removed selected entries
for (String currentKey : listOfEntriesToBeRemoved) {
var.remove(currentKey);
}
}
That works, but I'm sure there is a more elegant/efficient way of doing this.
To avoid a ConcurrentModificationException you can use an Iterator.
Iterator<String> it = map.keySet().iterator();
while (it.hasNext())
if (it.next().equalsIgnoreCase(currentKey))
break;
while (it.hasNext()) {
it.next();
it.remove();
}
If you wanted the most efficient solution, it would be to go straight to the appropriate entry in the first place. To do this you would have to only ever put lower case keys into the map (rather than putting any old strings and comparing using equalsIgnoreCase). Then, using reflection, you could access the Map.Entry object corresponding to currentKey.toLowerCase() and then, using reflection again, you could follow the links all the way through the map. None of this is possible without reflection because neither the entry corresponding to a key nor the links between entries are exposed through public API. I do not recommend reflection as your code could easily break in the future if the code for LinkedHashMap is changed.
For example... Adjacency list realiszation
public class Vertex {
String name;
boolean visited;
public Vertex(String name) {
this.name=name;
visited=false;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Object ob) {
return hashCode()==ob.hashCode();
}
public String toString() {
return name;
}
}
The main class
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
Map<Vertex,Vertex> m=new HashMap();
m.put(new Vertex("a"), new Vertex("b"));// a ---> b
m.put(new Vertex("a"), new Vertex("c"));// a ---> c
m.put(new Vertex("a"), new Vertex("d"));// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) {
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) {
pw.print(vert_to+" ");
}
pw.close();
}
}
It outputs:
All vertex from:
a
All vertices to:
d
But i need that "All vertices to: b c d"
How can I fix that?
A Map indeed stores a single value per key. You could, however, store a collection in value, say a Set:
Map<Vertex, Set<Vertex>> m = new HashMap<>();
Set<Vertex> set = new HashSet<>();
set.add(new Vertex("b"));
set.add(new Vertex("c"));
set.add(new Vertex("d"));
m.add (new Vertex("a"), set);
Alternatively, you can use one of the common implementations of this concept, such as Apache Commons Collections' MultiValueMap or Guava's HashMultiMap.
What you are asking for is called a "Multi Map".
If you are using Java 8 then this is quite neat, first you need a Map<Vertex, Collection<Vertex>>. I don't know what properties you need from the Collection, that you will have to investigate yourself.
As you have overridden equals and hashCode (incorrectly, but a valiant attempt), I will assume that you want to have the items unique by name. I will also assume that order matters, so LinkedHashSet seems a good choice.
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
Now, to add an item to the Map we need to first ensure that the Collection for that key is not null. This is exactly what the new Map.computeIfAbsent comes in.
final Vertex a = new Vertex("a");
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("b"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("c"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("d"));
So what this does is, when inserting a into the Map, if the Collection for that key is null, computes a new value for it.
Now to get all values for a key:
Collection<Vertex> values = graph.get(a);
You could wrap the Map<Vertex, Collection<Vertex>> in some sort of Graph class to hide the implementation details and to have neater code:
class Graph {
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
public void put(final Vertex key, final Vertex value) {
graph.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(value);
}
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key)).orElse(Collections.EMPTY_SET);
}
}
This also deals with returning an empty collection instead of null if a key is not present in the Map. Depending on your use case you might also want to wrap the returned Collection with Collections.unmodifiableCollection to prevent unwanted modifications:
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key))
.map(Collections::unmodifiableCollection)
.orElse(Collections.EMPTY_SET);
}
You could also use a Guava Multimap if you aren't averse to external libraries.
Using a Multimap for your problem, it could be written like that:
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
ListMultimap<Vertex,Vertex> m= ArrayListMultimap.create();
Vertex a = new Vertex("a"); // it's better to create each object once
Vertex b = new Vertex("b");
Vertex c = new Vertex("c");
Vertex d = new Vertex("d");
m.put(a,b);// a ---> b
m.put(a,c);// a ---> c
m.put(a,d);// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) { //exactly the same as in your code
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) { //exactly the same as in your code
pw.print(vert_to+" ");
}
pw.close();
}
To use Guava, just download the latest jar from here and add it to your libraries.
Explanation:
By definition, each java Map has a single key and a single value.
However, you can use a Collection (like a List), or an Array for value. This way, your Map will be defined like that:
Map<Vertex, List<Vertex>> m = new HashMap<>();
Each time you want to add an element value to the list of vertex key, you can do it that way:
List<Vertex> list = m.get(key);
if (list == null) {
list = new ArrayList<>();
}
list.add(value);
An easier way, is to use Guava's Multimaps. It is the same as a Map, but the value is a Collection. So, an ArrayListMultimap is quite what I described above. The way to use it, though is much simpler:
ListMultimap<Vertex, Vertex> m = ArrayListMultimap.create();
m.put(key, value1);
m.put(key, value2); //adds value2 to the key, which also contains value1
....
I have an object as Riziv with three variables as id, cnk and product. Then I search in a databank for this object and add it to a ArrayList as ArrayList<Riziv> list.
Now I should checkout if all object in his array are the same cnk then return true otherwise I should return all objects which are not the same cnk with error message.
public class Riziv{ String id, cnk, product; }
ArrayList<Riziv> list = getArrayListFromDatabank(id);
public void getDuplicatedWhichHasTheSameCnk(){
}
}
Using standard JVM structures (MultiMap is provided by guava), you can do that:
public List<Riviz> getDuplicates(final List<Riviz> l)
{
final HashMap<String, List<Riviz>> m = new HashMap<String, List<Riviz>>();
final List<Riviz> ret = new ArrayList<Riviz>();
String cnk;
for (final Riviz r: l) {
cnk = r.getCnk();
if (!m.contains(cnk))
m.add(cnk, new ArrayList<Riviz>());
m.get(cnk).add(r);
}
List<Riviz> tmp;
for (final Map.Entry<String, List<Riviz>> entry: m.entrySet()) {
tmp = entry.getValue();
if (tmp.size() == 1) // no dups
continue;
ret.addAll(tmp);
}
return ret;
}
ret will contain the duplicates. You can change that function to return a Map<String, Riviz> instead, and filter out entries where the list size is only one. You'll then get a map with the conflicting cnks as keys and a list of dups as values.
I am not clear exactly what you want however I suspect you want something like this.
MultiMap<Key, Riziv> multiMap =
List<Riziv> list =
for(Riziv r: list)
multiMap.put(r.getCnk(), r);
for(Key cnk: multiMap.keySet()) {
Collection<Riziv> sameCnk = multiMap.get(cnk);
// check size and compare entries
}
The multi-map will have the list of Riziv objects for each Cnk.
One way to do it is write a comparator to sort the list by cnk String and then compare each consecutive cnk String to the next, if you find a duplicate, they will be right next to eachother.
1.) Sort the list using a comparator by sorting on the cnk variable.
2.) Compare each element in the list to the next for duplicates.
There's probably many other ways to solve this, this is just the first that came to mind.
I did not test this so you have been forewarned lol:
ArrayList<Riziv> rizArray = new ArrayList<Riziv>();
//Sort the array by the CNK variable.
Collections.sort(rizArray, new Comparator<Riziv>(){
#Override
public int compare(Riziv arg0, Riziv arg1) {
//Return the comparison of the Strings.
//Use .compareToIgnoreCase if you want to ignore upper/lower case.
return arg0.getCnk().compareTo(arg1.getCnk());
}
});
//List should be in alphabetical order at this point.
List<Riziv> duplicates = new ArrayList<Riziv>();
Riziv rizPrevious = null;
for(Riziv riz: rizArray){
if(rizPrevious == null){
rizPrevious = riz;
continue;
}
if(riz.getCnk().compareTo(rizPrevious.getCnk()) == 0){
duplicates.add(riz);
}
rizPrevious = riz;
}