views:

227

answers:

5

I have a java.util.ArrayList<Item> and an Item object.

Now, I want to obtain the number of times the Item is stored in the arraylist.

I know that I can do arrayList.contains() check but it returns true, irrespective of whether it contains one or more Items.

Q1. How can I find the number of time the Item is stored in the list?

==================================================================================

Q2. Also, If the list contains more than one Item, then how can I determine the index of other Items because arrayList.indexOf(item) returns the index of only first Item every time?

+3  A: 

This is easy to do by hand.

public int countNumberEqual(ArrayList<Item> itemList, Item itemToCheck) {
    int count = 0;
    for (Item i : itemList) {
        if (i.equals(itemToCheck)) {
          count++;
        }
    }
    return count;
}

Keep in mind that if you don't override equals in your Item class, this method will use object identity (as this is the implementation of Object.equals()).

Edit: Regarding your second question (please try to limit posts to one question apiece), you can do this by hand as well.

public List<Integer> indices(ArrayList<Item> items, Item itemToCheck) {
    ArrayList<Integer> ret = new ArrayList<Integer>();
    for (int i = 0; i < items.size(); i++) {
        if (items.get(i).equals(itemToCheck)) {
            ret.add(i);
        }
    }
    return ret;
}
danben
Is there any other more efficient method because my list contains thousands of items and a particular item can be duplicated at most 4 or 5 times. So I think that its not worth to compare those thousands of items to find those 4 or 5 duplicates. Please don't suggest me to use `Set` because there is a solid reason for not using Set in my case.
Yatendra Goel
Think about the fact that to count items you will need ANYWAY to go through the whole list, since you will have to check them all to know the exact count.
Jack
If you want something that has a lower time complexity, you're out of luck - knowing nothing about the contents of your List, you must check every position. One optimization is to compare the `hashCode` of your item to the `hashCode` of each item in the List, but if they are equal then you must still check for equality using `equals()` as your hash function may have collisions. If you are checking for object identity only, there is no need to do this as `equals` will be comparing the memory addresses or something of the like.
danben
If this is something that must be done frequently and the time it takes is a performance drain, than a simple List is the wrong structure to use. Depending on what you're trying to do, perhaps you could modify Item to include a count, and then on adds search for the item and increment the count. Or create another structure to hold the counts. Etc. There's no magic way to search a list faster than a sequential traversal.
Jay
@Yatendra Goel Java can iterate a list with thousands ( and even hundreds of thousands ) objects in less than a second.
OscarRyz
+15  A: 

You can use Collections class:

public static int frequency(Collection<?> c, Object o)

Returns the number of elements in the specified collection equal to the specified object. More formally, returns the number of elements e in the collection such that (o == null ? e == null : o.equals(e)).

If you need to count occurencies of a long list many times I suggest you to use an HashMap to store the counters and update them while you insert new items to the list. This would avoid calculating any kind of counters.. but of course you won't have indices.

HashMap<Item, Integer> counters = new HashMap<Item, Integer>(5000);
ArrayList<Item> items = new ArrayList<Item>(5000);

void insert(Item newEl)
{
   if (counters.contains(newEl))
     counters.put(newEl, counters.get(newEl)+1);
   else
     counters.put(newEl, 1);

   items.add(newEl);
 }

A final hint: you can use other collections framework (like Apache Collections) and use a Bag datastructure that is described as

Defines a collection that counts the number of times an object appears in the collection.

So exactly what you need..

Jack
wow never knew about this method. Javadoc found here: http://java.sun.com/javase/6/docs/api/java/util/Collections.html#frequency%28java.util.Collection,%20java.lang.Object%29
SB
Your first method is more suitable to my need. But there is one problem. If I found more than one items in the list then how to retrieve those other items from the list?
Yatendra Goel
If they're equal, why bother retrieving them? You already know what's inside! Or are there fields that don't enter your `equals` comparison? Or are you looking to do more than just retrieve, like maybe deleting?
Carl Smotricz
A: 

As the other respondents have already said, if you're firmly committed to storing your items in an unordered ArrayList, then counting items will take O(n) time, where n is the number of items in the list. Here at SO, we give advice but we don't do magic!

As I just hinted, if the list gets searched a lot more than it's modified, it might make sense to keep it sorted. If your list is sorted then you can find your item in O(log n) time, which is a lot quicker; and if you have a hashcode implementation that goes well with your equals, all the identical items will be right next to each other.

Another possibility would be to create and maintain two data structures in parallel. You could use a HashMap containing your items as keys and their count as values. You'd be obligated to update this second structure any time your list changes, but item count lookups would be o(1).

Carl Smotricz
A: 

I could be wrong, but it seems to me like the data structure you actually want might be a Multiset (from google-collections/guava) rather than a List. It allows multiples, unlike Set, but doesn't actually care about the order. Given that, it has a int count(Object element) method that does exactly what you want. And since it isn't a list and has implementations backed by a HashMap, getting the count is considerably more efficient.

ColinD
A: 

Thanks for your all nice suggestion. But this below code is really very useful as we dont have any search method with List that can give number of occurance.

void insert(Item newEl) 
{ 
   if (counters.contains(newEl)) 
     counters.put(newEl, counters.get(newEl)+1); 
   else 
     counters.put(newEl, 1); 

   items.add(newEl); 
 } 

Thanks to Jack. Good posting.

Thanks,

Binod Suman

http://binodsuman.blogspot.com

Ayush Suman