Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
Working with Lists and Maps, I started thinking, why Map method for adding Object is called put and for List it is add?
It is just developers will, or there was something under naming those methods different.
May be the methods names let the developer know while adding to Map/List what kind of data structure he is working with?
Or those names describes the way they works?
The difference is :
.add() means to insert something at the end or wherever you want to(you know where to add) whereas
.put() means to add an element wherever it needs to be placed, not necessarily at the end of the Map, because it all depends on the Key to be inserted (you don't know where to add).
To me, it has some cause.
After all, List is a dynamic array, which internally consists a logical index where we are adding.
And map internally carry a bucket of key and value pair. So kind of we are putting something into the bucket.
It can be stated as so because to get a clear understanding.
As java is a 3rd level human understandable language this also can state as a simple English for better understanding.
Collection#add() can be seen that you add your value to a pool of something (an implementation of Collection<E> defines what pool actually is).
Whereas with Map#put() you associate your value with the key which potentially already had a value associated with it.
Add will always add an entry to the end of a list.
Put injects an entry into the map if the key does not already exist; if the key already exists, the value is updated.
Thus the operations are different. On some level, the authors of the API have to make decisions that balance out various concerns. Add to a set has some aspects of add to a list and put to a map, in that adding an "equal" entry has no effect.
For this you should just read the Java docs for add and put.
They are 2 different function, that take completely incompatible inputs, and return completely incompatible values. They are 2 completely separate and distinct functions that behave completely differently (other than they both are for adding elements to a collection (the concept, not interface. As map doesn't implement that interface)).
From the docs
PUT
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value. (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
ADD
Appends the specified element to the end of this list (optional operation).
Lists that support this operation may place limitations on what elements may be added to this list. In particular, some lists will refuse to add null elements, and others will impose restrictions on the type of elements that may be added. List classes should clearly specify in their documentation any restrictions on what elements may be added.
List :- If i say i'm adding some items to the some Container ill say that i have added the items to the container.Here we are more concentrate on the new item Addition to the existing container or List (in java).
Map :- If i want to put some of the things to the some locker or my computer which is already having the things which i dont care about i just have to put not add.
Here we are concentrate to addition of new data to the locker or Map (in java) regardless of existing the thing.
Real time example:- you add sugar to the tea keeping in mind the amount which is already their.you put your cloths to the Clothing Store regarding their exist any cloths or not.
In java side :-
if you list is like this :-
List<String> list = new ArrayList<String>();
list.add("java");
list.add("php");
list.add("python");
list.add("perl");
list.add("c");
list.add("lisp");
list.add("c#");
and you want to add something to the list you have to care about the existing thing because if it is list it will add duplicate and if set then don't duplicate.
If you create a Map.
Map<String, Object> foodData = new HashMap<String, Object>();
foodData.put("penguin", 1);
foodData.put("flamingo", 2);
and again you are adding something foodData.put("penguin", 3); you don't have to worry about adding and update the data internally.
I think if you get into etymology we can only guess that since when you place a value into a list you always increase the list length, however if you put the value into a map you would not necessary increase the number of map entries (if the key already exists)
Related
I want to make a set of some type of collection (not sure which one yet) as a way of "storing duplicates" in a set. For example if I wanted to add the integer 5 with 39 additional copies I could put it into an arraylist at index 39. Thus if I were to get the size of the arraylist, I would know how many copies of 5 existed within the set.
There are a few other ways I could implement this but I have yet to decide on one. The main issue I'm having with implementing this is that I'm not sure how I can "dynamically" make arraylists (or whatever collection I may end up using) so that whenever someone were to call mySet.add(object), the object is first inserted into a unique arraylist then into the set itself.
Can anyone give me some ideas on how I could approach this?
EDIT:
Sorry I should have been more clear in my question. The point of the code that I'm writing is that we have a set-like collection that allows duplicates. And yes some of the associated methods will be re-written/will have to be re-written. Also my code should be written under the assumption that we do not know what type of object is being inserted(only one data type per set though) nor how many instances of the same object will be added nor how many different unique objects will be added.
I would rather go for using a Map like
HashMap list <Object, Integer>
where Object is the Object that you want to count and Integer is the count
You could try guava's MultiSet, I think it's what you want.
It can store the count of each object. What you need to do is just
multiSet.put(object);
And if it is put for the first time, like you said, a new list will be created, or its count will added by one.
So i have a code snippet here. I go this issue while i was discussing some code with my friend
Map<Integer , List<String>> myMap = new HashMap<Integer , List<String>>();
List<String> list = new ArrayList<String>();
myMap.put(45,list);
List<String> lst = myMap.get(45);
lst.add("String1");
lst.add("String2");
lst.add("String3");
System.out.println(myMap.get(45));
My question here is.
-> If its ok to modify the list outside the map through another reference? I am asking from OOP design point of view.
That is completely ok, IMHO
When you write
List<String> lst = myMap.get(45);
Still it is refering to the value in the map, for the key 45.
Once you get the value(reference to the list), It's up to you what you are doing with it.
If its ok to modify the list outside the map through another reference? I am asking from OOP design point of view.
It really depends on the context in which you're modifying it. If you plan on doing this a lot, with a lot of different values, then you're quickly going to find yourself with very confusing code that is difficult to debug and to follow.
BUT, in your example, you first load it from the map, then you edit it. It's completely clear that the data is coming from your Map object. Provided you make it clear with comments and documentation, especially when you're passing this reference between other methods, this isn't bad practise at all.
It is OK, provided that you take care of any potential synchronizations; e.g. if there are multiple threads that might be modifying the map and / or the list.
You might be confusing this with the case where you modify a key object. That is distinctly NOT ok if the modification breaks the hash table invariants; e.g.
if it causes either the key's hashcode to change, or
if it causes the key to give a different result when compared with some other key used in the table.
I am asking from OOP design point of view.
I'd say that OO design is neutral on this issue. You are using a Java interface (i.e. Map) that doesn't take control of the values. You are not violating encapsulation because the values are not encapsulated by the Map abstraction.
Whether this is sound design from the application perspective depends on the overall design. We can't make a judgement one way or another without understanding the context.
Every reference has a scope, it is your take(based on your requirement) whether you want the Map to be accessed through multiple reference or through a single reference.
It's OK.
After you have added numbers to the list in lines 5-7 in your code snippet, and then you get the list from the map again in line 8, the list you get from the map will have the extra numbers you just added.
That depends on what you want to do with the list and what your requirements are.
I'd say it is ok-ish but it might be better to encapsulate that in another object.
Consider the question what to do with empty lists, should they be removed or kept?
Encapsulation would allow you to ensure that empty lists are removed, since the user would then only access the wrapper, not the list directly.
Btw, with HashMap you have to change the list outside the map ;)
ArrayList is mutable. It is resizeable and keeps the same reference after modification. To have immutable list you should use following code.
List<String> list = Collections.unmodifiableList(new ArrayList<String>());
If you define list above way, than you can't modify it.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
Today the interviewer asked me: How does Set guarantees non duplicates?
The answer lies in the source code of add method. For example in source code of TreeSet the add method is implemented as follows:
public boolean add(E e)
{
return m.put(e, PRESENT)==null;
}
Where, PRESENT is an object of Object class. And m is the object of NavigableMap. This NavigableMap m is used to store the element e as key and PRESENT as its value to the given key e. Consequently every key in m has same object PRESENT. The put method of Map as defined within oracle doc is :
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
...
...
Returns: the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
So, When you put the duplicate element within set this element is put in the NavigableMap as key with value PRESENT. If this key was not present in NavigableMap then put method returns null and hence
m.put(e,PRESENT)==null returns true and we come to know that the element is added. And if the key is already present in NavigableMap then put method overrided the value for the key e within NavigableMap with PRESENT and returns the old value (which is PRESENT) and hence
m.put(e,PRESENT)==null returns false and we come to know that the element is not added.
From a specification point of view, it achieves it by e.g. specifying what the add method must do if you try and add a duplicate. The documentation for the add method says this, for example:
Adds the specified element to this set if it is not already present
(optional operation). More formally, adds the specified element e to
this set if the set contains no element e2 such that (e==null ?
e2==null : e.equals(e2)). If this set already contains the element,
the call leaves the set unchanged and returns false. In combination
with the restriction on constructors, this ensures that sets never
contain duplicate elements.
From the same page (http://docs.oracle.com/javase/6/docs/api/java/util/Set.html):
The additional stipulation on constructors is, not surprisingly, that all constructors must create a set that contains no duplicate elements (as defined above).
(For completeness, there are also stipulations with regard to equals and hashCode that ensure that Set properly models the set abstraction.)
Set is an abstract data type that can be implemented in many ways. On its own it's a specification of a contract; as such it does not guarantee anything. It's up to the implementation of the interface to guarantee that the contract is fulfilled.
Therefore it's more interesting to look at how and why the implementations work. Some common implementations are:
Hash table, as implemented in Java by HashSet
Balanced tree, as implemented in Java by TreeSet
Bit set (for special types), as implemented in Java by EnumSet and BitSet
Skip lists, as implemented by ConcurrentSkipListSet
Naive arrays: scan the array for the element before adding it; not frequently used. Implemented in Java as CopyOnWriteArraySet
In a job interview you would have replied with the above and offered to explain the details of any one implementation. The interviewer should already know some of these and it wouldn't have been to your benefit to start rambling about them unless asked.
I am working on an application with a number of custom data classes. I am taking input for my application from 2 different places and want to cross-reference between the two to help ensure the data is accurate.
I have a Map.Entry<String,HashMap<String, Integer>> object called chromosome, where each value is called a marker.
I also have a custom object called IndividualList individuals which extends HashMap<Integer,Individual> where each Individual has a method Genotype getGenotype() which returns the non-static variable genotype. Genotype extends HashMap<String,String[]>
I want to look at each the key for all my marker objects and check whether each of them are present as a key in any Individual's genotype. Every Individual has the same keys in its genotype so I only need to test for one Individual.
The problem I am facing is which Individual to test, as because it is a HashMap I cannot simply just arbitrarily choose the first element, so what I am doing at the moment is taking the values of individuals as a Collection then converting these to an ArrayList<Individual> then taking the first of these elements (which is just an arbitrary one as HashMap is unordered) to get an Individual then taking this Individual's genotype and comparing marker.getKey() with the keys in the genotype. Like so :
for(Map.Entry<String, MarkerPosition> marker : chromosome.getValue().entrySet())
if(!(new ArrayList<Individual>(individuals.values()).get(0)
.getGenotype().containsKey(marker.getKey())))
errors.add("Marker " + marker.getKey() + " is not present in genotype");
But as you can see, this is horrid and ugly and far too complicated, so I was wondering if there is a much simpler way of achieving what I want that I am missing.
Thanks!
Why can you not arbitrarily choose the first element of a HashMap?
individuals.entrySet().iterator().next()
individuals.values().iterator().next()
This will probably be the same entry each time. You should make sure the map is not empty to avoid an exception.
...This question is really confusingly phrased and difficult to understand, but I'm not clear on why you don't just use
individuals.values().iterator().next()
instead of new ArrayList<Individual>(individuals.values()).get(0).
(If you can use third-party libraries, your code would probably be significantly clearer overall if you used a Guava Table, which is a general-purpose, significantly "cleaner" replacement for a Map<K1, Map<K2, V>>. Disclosure: I contribute to Guava.)
Why does java.util.Map.values() allow you to delete entries from the returned Collection when it makes no sense to remove a key value pair based on the value? The code which does this would have no idea what key the value(and hence a key) being removed is mapped from. Especially when there are duplicate values, calling remove on that Collection would result in an unexpected key being removed.
it makes no sense to remove a key value pair based on the value
I don't think you're being imaginative enough. I'll admit there probably isn't wide use for it, but there will be valid cases where it would be useful.
As a sample use case, say you had a Map<Person, TelephoneNumber> called contactList. Now you want to filter your contact list by those that are local.
To accomplish this, you could make a copy of the map, localContacts = new HashMap<>(contactList) and remove all mappings where the TelephoneNumber starts with an area code other than your local area code. This would be a valid time where you want to iterate through the values collection and remove some of the values:
Map<Person, TelephoneNumber> contactList = getContactList();
Map<Person, TelephoneNumber> localContacts = new HashMap<Person, TelephoneNumber>(contactList);
for ( Iterator<TelephoneNumber> valuesIt = localContacts.values().iterator(); valuesIt.hasNext(); ){
TelephoneNumber number = valuesIt.next();
if ( !number.getAreaCode().equals(myAreaCode) ) {
valuesIt.remove();
}
}
Especially when there are duplicate values, calling remove on that Collection would result in an unexpected key being removed.
What if you wanted to remove all mappings with that value?
It has to have a remove method because that's part of Collection. Given that, it has the choice of allowing you to remove values or throwing an UnsupportedOperationException. Since there are legitimate reasons that you might want to remove values, why not choose to allow this operation?
Maybe there's a given value where you want to remove every instance
of it from the Map.
Maybe you want to trim out every third
key/value pair for some reason.
Maybe you have a map from hotel
room number to occupancy count and you want to remove everything from
the map where the occupancy count is greater than one in order to
find a room for someone to stay in.
...if you think about it more
closely, there are plenty more examples like this...
In short: there are plenty of situations where this might be useful and implementing it doesn't harm anyone who doesn't use it, so why not?
I think there is quite often a use for removing a value based on a key; other answers show examples. Given that, if you want to remove a certain value, why would you only want one particular key of it removed? Even if you did, you'd have to know which key you wanted to remove (or not, as the case may be), and then you should just remove it by key anyway.
The Collection returned is a special Collection, and its semantics are such that it knows how values in it relate back to the Map it came from. The javadoc indicates what Collection operation the returned collection supports.