On Sun, 02 Aug 2009 20:39:32 +0200, "Didier \"Ptitjes\"" <ptitjes free fr> wrote:
Quikee wrote:In what way should remove_all work in case of removing the same items. Currently there is an inconsistency in this behavior from remove_all on AbstractCollection and the implementation in ArrayList. The AbstractCollection implementation will call remove for every element which will in case of n same items in list 1 and m same items in incoming list 2 remove n-m items. For example: list1 has items 1,1,1,1,1 and list2 has items 1,1,1 after remove_all in list1 would remain items 1,1 The implementation on ArrayList will always remove all items from the list if the incoming list has such an item. So in the same example as above list1 after the call would not have any items. I have looked also how Java's ArrayList behaves in such a case and it did behave in a different way as above. The Java's ArrayList treated the incomming collection as a set and did delete only one element from the list1. So the example would look like this: list1 has items 1,1,1,1,1 and list2 has items 1,1,1 after remove_all in list1 would remain items 1,1,1,1 Which of this behavior would you prefer?That's a good thing you point here. IMHO we should explicit API contracts in the collection interfaces. I would prefer that remove is said to remove the first element. And that remove_all removes every element instances. IMHO this will enable to respect the same API contract for multi-sets.
remove_all() is just a bad name to begin with. There are two separate ideas here: 1) removing all items in list1 that have a matching item in list2 1,1,1 from 1,1,1,1,1 gives an empty list eg. impl.: iterate over items in list1, checking list2 for a matching item, and remove it if found. ("greedy" matching?) This is more like what I thought of when I heard the name remove_all()... Except that my immediate thought was "take this single item, and remove any identical items from the list". To my thinking, remove_all() given a list would be move like #2 below... 2) removing all items in list1 that have a corresponding item in list2 1,1,1 from 1,1,1,1,1 gives 1,1 eg. impl.: iterate over items in list2, checking list1 for a matching item, and remove it if found. I'd personally call this subtract() or remove_from() or something. I've personally used this type of operation more often than the operation in #1 above. (If practical, making remove_from() a method of list2 would seem the most logical.) Although the one operation I use more than either of these, is a three-way-split. Given two lists, produce the three lists containing those items only in list1, those items only in list2, and those items in both lists. Of course even there, there's a question of whether to use a greedy or non-greedy matching of items.
As you can read in Apache Commons Collections, which build upon and derives from Java Collections, their Bag interfaces explicitly override the defined behavior for contains|remove|*All methods. [1] Thus I would prefer if our Collection interface already defines a such API contract: remove_all removes all the element occurrences. In simple sets, it would obviously remove only one instance.
How about adding a "remove all matching elements" argument to the mix, to determine which of the two methods to use? I don't think you're going to make everyone happy if you pick either one over the other... Otherwise, the function names that come to mind for all these combinations are: list1.remove(item) list1.remove_by_list(list2) list1.remove_all(item) list1.remove_all_by_list(list2) list2.remove_from(list1) list2.remove_all_from(list2) and lastly for completion... list1.split3way(list2, only1?, only2?, both?) - where the three target list arguments may be undefined to ignore that case, and should be existing lists into which the relevant items will be added (allowing the result of several such splits to be combined). -- Fredderic Debian/unstable (LC#384816) on i686 2.6.29-2-686 2009 (up 7 days, 14:45)
Attachment:
signature.asc
Description: PGP signature