I have java object Map<Integer, SortedMap<Integer, Pair<Integer, String>>> data. I am passing this object to recursive method to build objects of each key in the above map. Please see the example below.
For ex,
<1 - <1, Pair<1, 'A'>>
<2 - <1, Pair<1, 'A'>>
<2, Pair<2, 'B'>>
I want to check the circular dependency on the above map. Please see the example below.
<9994 - <1, Pair<9995, 'X'>>
<2, Pair<2, 'B'>>
<9995 - <1, Pair<9994, 'Y'>>
<2, Pair<2, 'B'>>
Above 9994 contains 9995 and 9995 contains 9994. This is invalid and should error out the programme.
Can anyone suggest me the best way to perform this validation?
Thanks.
private static Boolean validate(
Map> input,
Set object) throws Exception {
Boolean result = true;
for (Pair cal : input.values()) {
if (!object.add(cal.left))
return false;
result = validate(get(cal.left), object);
}
return result;
}
The check for circular dependency could be implemented via Depth-first-search. Fo this, either the objects to be checked would have to be changed to contain a flag (which would indicate whether they have already been visited) or some auxiliary data structure like a list or hashmap would contain the visited nodes.
I would recommend, you use the recursive function to put the keys in a HashSet. The HashSet "add" method returns true if the insertion was successful and false otherwise. So if there was a duplicate the add method will return false. You can use that as your validation.
If you can post some initial code snippet, we can try to help with this solution.
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
You can track the visited nodes in a collection in all levels of recursion. Check before processing if the node is already visited.
Related
If I have a HashMap hashM, an ArrayList arrayL. If I would like to use an if statement to check whether hashM has all the elements in arrayL, how can I do that?
I cm currently using something like
if (hashM.values().containsAll(arrayL.getPreReqs()))
However it doesn't work properly.
Dear all thanks for the answers!
Actually containsAll works however the way I structure the my codes is wrong so that I got wrong outcomes. Now it has been fixed.
Cheers!
Given
Map<?,?> map = new HashMap<?,?>();
List<?> list = new ArrayList<?>();
The approach you tried (well, nearly, as pointed out by Marko Topolnik) is indeed correct:
if (map.values().containsAll(list)) { ... }
(Or map.keySet().containsAll(list) if you were interested in the map keys instead of values.)
For this to work as expected for custom types, you of course must have implemented equals() and hashcode() correctly for them. (See e.g. this question or better yet, read Item 9 in Effective Java.)
By the way, when working with Java Collections, it is good practice to define fields and variables using the interfaces (such as List, Set, Map), not implementation types (e.g. ArrayList, HashSet, HashMap). For example:
List<String> list = new ArrayList<String>();
Map<Integer, String> map = new HashMap<Integer, String>();
Similarly, a more "correct" or fluent title for your question would have been "How to check whether a Map has all the elements of a List?". Check out the Java Collections tutorial for more info.
Your code is correct except..
if (hashM.values().containsAll(arrayL)) {....}
[EDIT]
You can use HashMap.containsValue(Object value)
public boolean containsList(HashMap<K, V> map, List<V> list) {
for(V value : list) {
if(!map.containsValue(value)) {
return false;
}
}
return true;
}
Your code should work - but will not be particularly efficient. You need to compare every element in the list with every element in the map.
If (and only if) you can easily extract the key of the map from the elements then you would be better off looping through your List and for each element do map.containsKey(getKey(elem)), this will be much faster.
If you are doing this sort of comparison a lot and you cannot map from element to key then it may be worth keeping a HashSet of the values for this purpose.
I agree with JoniK. This can be done in a single line like this.
if(hashM.values().containsAll(arrayL)) {// put your code here that will be returned}
I've seen other questions about getting objects from Set's based on index value and I understand why that is not possible. But I haven't been able to find a good explanation for why a get by object is not allowed so thought I would ask.
HashSet is backed by a HashMap so getting an object from it should be pretty straightforward. As it is now, it appears I would have to iterate over each item in the HashSet and test for equality which seems unnecessary.
I could just use a Map but I have no need for a key:value pair, I just need a Set.
For example say I have Foo.java:
package example;
import java.io.Serializable;
public class Foo implements Serializable {
String _id;
String _description;
public Foo(String id){
this._id = id
}
public void setDescription(String description){
this._description = description;
}
public String getDescription(){
return this._description;
}
public boolean equals(Object obj) {
//equals code, checks if id's are equal
}
public int hashCode() {
//hash code calculation
}
}
and Example.java:
package example;
import java.util.HashSet;
public class Example {
public static void main(String[] args){
HashSet<Foo> set = new HashSet<Foo>();
Foo foo1 = new Foo("1");
foo1.setDescription("Number 1");
set.add(foo1);
set.add(new Foo("2"));
//I want to get the object stored in the Set, so I construct a object that is 'equal' to the one I want.
Foo theFoo = set.get(new Foo("1")); //Is there a reason this is not allowed?
System.out.println(theFoo.getDescription); //Should print Number 1
}
}
Is it because the equals method is meant to test for "absolute" equality rather than "logical" equality (in which case contains(Object o) would be sufficient)?
Java Map/Collection Cheat Sheet
Will it contain key/value pair or values only?
1) If it contains pairs, the choice is a map. Is order important?
. 1-1) If yes, follow insertion order or sort by keys?
. . 1-1-1) If ordered, LinkedHashMap
. . 1-1-2) If sorted, TreeMap
. 1-2) If order is not important, HashMap
2) If it stores only values, the choice is a collection. Will it contain duplicates?
. 2-1) If yes, ArrayList
. 2-2) If it will not contain duplicates, is primary task searching for elements
(contains/remove)?
. . 2-2-1) If no, ArrayList
. . 2-2-2) If yes, is order important?
. . . 2-2-2-1) If order is not important, HashSet
. . . 2-2-2-2) If yes, follow insertion order or sort by values?
. . . . 2-2-2-2-1) if ordered, LinkedHashSet
. . . . 2-2-2-2-2) if sorted, TreeSet
A Set is a Collection of objects which treats a.equals(b) == true as duplicates, so it doesn't make sense to try to get the same object you already have.
If you are trying to get(Object) from a collection, a Map is likely to be more appropriate.
What you should write is
Map<String, String> map = new LinkedHashMap<>();
map.put("1", "Number 1");
map.put("2", null);
String description = map.get("1");
if an object is not in the set (based on equals), add it, if it is in the set (based on equals) give me the set's instance of that object
In the unlikely event you need this you can use a Map.
Map<Bar, Bar> map = // LinkedHashMap or ConcurrentHashMap
Bar bar1 = new Bar(1);
map.put(bar1, bar1);
Bar bar1a = map.get(new Bar(1));
If you want to know that new Foo("1"); object is already present in the set then you need to use contains method as:
boolean present = set.contains(new Foo("1"));
The get kind of method i.e. set.get(new Foo("1")); is not supported because it doesn't make sense. You are already having the object i.e. new Foo("1") then what extra information you would be looking through get method.
Your last sentence is the answer.
get(Object o) would run through the HashSet looking for another object being equal to o (using equals(o) method). So it is indeed the same as contains(o), only not returning the same result.
HashSet is a little bit simplier than HashMap. If you don't need the features of HashMap, why use it? If the method like getObject(ObjectType o) was implemented by Java we dont need to iterate over the set after calling contain() methode...
The reason why there is no get is simple:
If you need to get the object X from the set is because you need something from X and you dont have the object.
If you do not have the object then you need some means (key) to locate it. ..its name, a number what ever. Thats what maps are for right.
map.get( "key" ) -> X!
Sets do not have keys, you need yo traverse them to get the objects.
So, why not add a handy get( X ) -> X
That makes no sense right, because you have X already, purist will say.
But now look at it as non purist, and see if you really want this:
Say I make object Y, wich matches the equals of X, so that set.get(Y)->X. Volia, then I can access the data of X that I didn have. Say for example X has a method called get flag() and I want the result of that.
Now look at this code.
Y
X = map.get( Y );
So Y.equals( x ) true!
but..
Y.flag() == X.flag() = false. ( Were not they equals ?)
So, you see, if set allowed you to get the objects like that It surely is to break the basic semantic of the equals. Later you are going to live with little clones of X all claming that they are the same when they are not.
You need a map, to store stuff and use a key to retrieve it.
if you only want know what are in the Hashset, you can use .toString(); method to display all Hashset Contents separated by comma.
A common use case of a get method on Set might be to implement an intern set. If that's what you're trying to achieve, consider using the Interner interface and Interners factory from Google Guava.
I've got the same problem as the thread author and I've got a real reason why
a Set should have a get method:
I overwrote equals of e.g. X, the content of the set Set and so the contained
object is not necessarily the same as the checked one. In my scenario I'll remove
semantic doubles in an other collection and enrich the "original" with some relations
of the "double" so I need the "original" to be able to drop the double.
get(Object o) is useful when we have one information linked to other information just like key value pair found in HashMap .So using get() method on one information we can get the second information or vice-versa.
Now, if HashSet provides get(Object o) method you need to pass an object. So if you have the object to pass to the get(Object o) method that means you already have the object, then what is need of get(Object o) method.
As everyone mentioned before, there is no such method and for good reasons. That being said, if you wish to get a certain object from a HashSet in java 8 using a one-liner (almost), simply use streams. In your case, it would be something like:
Foo existing = set.stream().filter(o -> o.equals(new Foo("1"))).collect(Collectors.toList()).iterator().next();
Note that an exception will be thrown if the element doesn't exist so it is technically not a one-liner, though if the filter is properly implemented it should be faster than a traditional iteration over the collection elements.
Needs:
Storing objects of a class which overrides equals and hash code
Will be looping and shoving objects into the datastructure
Need to be able to call contains to check whether a certain object is stored in the structure
If contains returns true then fetch that specific object from the structure and call a certain getter on that object
Options I've considered:
Map - this works for all the needs but I don't really have a map (key and a value). all I have is bunch of objects. Would it be a good practice to forcefully use a map by storing objects as key and integer or something in the value?
Set would work, however, it doesn't have a fetch method like get.
List would also work, but it doesn't have a method to fetch that is non index based. Meaning, once contains returns true I'll have to loop through the list to find the index of my particular object and then fetch it.
I'm open to using different libraries like apache commons or guava for example.
List would also work, but it doesn't have a method to fetch that is non index based.
List has an indexOf(Object) method which will do exactly what you want.
Although the best thing to use in this scenario would be a Map, because it offers fast retrieval based on Key-Value pair.
But List also allows to fetch data based on index.
So, you can use either a List or a Map. But to make your task easier, I would prefer a Map. Because i case of Map you won't have to search for an index of an Object, then get the Object at that index. Fetching is just a one-line operation.
// When using a List.
List<String> myList = new ArrayList<String>();
if (myList.contains("rohit")) {
myList.get(myList.indexOf("rohit"));
}
// When using Map.
Map<String, String> myMap = new HashMap<String, String>();
// You can directly fetch your object, based on some Key if you have one..
myMap.get("key");
You need a set. You don't need a fetch method (you think you do), because like you said you only have a bunch of objects. And since these use equals and hashCode, a set is exactly what you need.
Of course a map could do as well, because its keys is a set as well, but in the end you need to better specify your requirements, as it appears you are a bit confused as to the purpose of your data structure. From what I understand, you do not need a map indeed.
A hash set implementation will do. Here is what you can do with it all:
class Foo
{
final String name;
Foo(String name)
{
this.name = name;
}
boolean equals(Object obj)
{
return (obj instanceof Foo) && ((Foo)obj).name.equals(name);
}
}
Set<Foo> fooSet = new HashSet<Foo>();
fooSet.add(new Foo("someFoo"));
assert fooSet.contains(new Foo("someFoo"));
I have two lists with different objects in them.
List<Object1> list1;
List<Object2> list2;
I want to check if element from list1 exists in list2, based on specific attribute (Object1 and Object2 have (among others), one mutual attribute (with type Long), named attributeSame).
right now, I do it like this:
boolean found = false;
for(Object1 object1 : list1){
for(Object2 object2: list2){
if(object1.getAttributeSame() == object2.getAttributeSame()){
found = true;
//also do something
}
}
if(!found){
//do something
}
found = false;
}
But I think there is a better and faster way to do this :)
Can someone propose it?
Thanks!
If you just need to test basic equality, this can be done with the basic JDK without modifying the input lists in the one line
!Collections.disjoint(list1, list2);
If you need to test a specific property, that's harder. I would recommend, by default,
list1.stream()
.map(Object1::getProperty)
.anyMatch(
list2.stream()
.map(Object2::getProperty)
.collect(toSet())
::contains)
...which collects the distinct values in list2 and tests each value in list1 for presence.
To shorten Narendra's logic, you can use this:
boolean var = lis1.stream().anyMatch(element -> list2.contains(element));
You can use Apache Commons CollectionUtils:
if(CollectionUtils.containsAny(list1,list2)) {
// do whatever you want
} else {
// do other thing
}
This assumes that you have properly overloaded the equals functionality for your custom objects.
There is one method of Collection named retainAll but having some side effects for you reference
Retains only the elements in this list that are contained in the
specified collection (optional operation). In other words, removes
from this list all of its elements that are not contained in the
specified collection.
true if this list changed as a result of the call
Its like
boolean b = list1.retainAll(list2);
Loius answer is correct, I just want to add an example:
listOne.add("A");
listOne.add("B");
listOne.add("C");
listTwo.add("D");
listTwo.add("E");
listTwo.add("F");
boolean noElementsInCommon = Collections.disjoint(listOne, listTwo); // true
faster way will require additional space .
For example:
put all items in one list into a HashSet ( you have to implement the hash function by yourself to use object.getAttributeSame() )
Go through the other list and check if any item is in the HashSet.
In this way each object is visited at most once. and HashSet is fast enough to check or insert any object in O(1).
According to the JavaDoc for the .contains(Object obj):
Returns true if this list contains the specified element. More
formally, returns true if and only if this list contains at least one
element e such that (o==null ? e==null : o.equals(e)).
So if you override your .equals() method for your given object, you should be able to do: if(list1.contains(object2))...
If the elements will be unique (ie. have different attributes) you could override the .equals() and .hashcode() and store everything in HashSets. This will allow you to check if one contains another element in constant time.
to make it faster, you can add a break; that way the loop will stop if found is set to true:
boolean found = false;
for(Object1 object1 : list1){
for(Object2 object2: list2){
if(object1.getAttributeSame() == object2.getAttributeSame()){
found = true;
//also do something
break;
}
}
if(!found){
//do something
}
found = false;
}
If you would have maps in stead of lists with as keys the attributeSame, you could check faster for a value in one map if there is a corresponding value in the second map or not.
Can you define the type of data you hold ? is it big data ? is it sorted ?
I think that you need to consider different efficiency approaches depending on the data.
For example, if your data is big and unsorted you could try and iterate the two lists together by index and store each list attribute in another list helper.
then you could cross check by the current attributes in the helper lists.
good luck
edited : and I wouldn't recommend overloading equals. its dangerous and probably against your object oop meaning.
org.springframework.util.CollectionUtils
boolean containsAny(java.util.Collection<?> source, java.util.Collection<?> candidates)
Return true if any element in 'candidates' is contained in 'source'; otherwise returns false
With java 8, we can do like below to check if one list contains any element of other list
boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();
I'm looking for a method like:
myMap.containsKeyStartingWith("abc"); // returns true if there's a key starting with "abc" e.g. "abcd"
or
MapUtils.containsKeyStartingWith(myMap, "abc"); // same
I wondered if anyone knew of a simple way to do this
Thanks
This can be done with a standard SortedMap:
Map<String,V> tailMap = myMap.tailMap(prefix);
boolean result = (!tailMap.isEmpty() && tailMap.firstKey().startsWith(prefix));
Unsorted maps (e.g. HashMap) don't intrinsically support prefix lookups, so for those you'll have to iterate over all keys.
From the map, you can get a Set of Keys, and in case they are String, you can iterate over the elements of the Set and check for startsWith("abc")
To build on Adel Boutros answer/comment about the efficiency of iterating keys, you could encapsulate key iteration in a Map subclass or decorator.
Extending HashMap would give you a class to put the method in and keep map-specific code out of your method, so lowering complexity and making the code more natural to read.