Hi,
Let’s say I have a TClonesArray of derived classes of TObjects in a root tree. According to the root manual, virtual function TObject::IsEqual() can be overridden to determine the behavior of TObject::FindObject(). That is if I were to defined a derived class of TObject to be equal if (let’s say) 2 of its data member matches (these data members are acting as keys), then the FindObject can be used to find TObjects in the TClonesArray based on this key. But what if there are multiple TObjects that matches this key? How does one iterate over the list? FindObject(const TObject* obj) only returns one pointer to a TObject. So it’s not obvious to me (nor does the manual mentions this) how one can iterate over findings that yields more than one match to the key being searched. Is there an example somewhere on how to achieve this? Thanks!
[quote=“jade2”]Hi,
Let’s say I have a TClonesArray of derived classes of TObjects in a root tree. According to the root manual, virtual function TObject::IsEqual() can be overridden to determine the behavior of TObject::FindObject(). That is if I were to defined a derived class of TObject to be equal if (let’s say) 2 of its data member matches (these data members are acting as keys), then the FindObject can be used to find TObjects in the TClonesArray based on this key. But what if there are multiple TObjects that matches this key? How does one iterate over the list? FindObject(const TObject* obj) only returns one pointer to a TObject. So it’s not obvious to me (nor does the manual mentions this) how one can iterate over findings that yields more than one match to the key being searched. Is there an example somewhere on how to achieve this? Thanks![/quote]
I’m afraid all what you can do is to iterate over a sequence (good that you know its type exactly - you know how to iterate ) in a manually written loop calling IsEqual - that’s what’s going on in FindObject implementations, the only difference you do not stop on the first object found, but (probably ‘process’ this object and then) continue.
IMHO the problem is this interface is … too generic and/too non-generic at the same time
What would you expect from such a function? Should it return another container with all pointers from your collection that are ‘equal’?
Iterators/ranges will not help here (what if your collection contains objects you’re interested in but with “gaps” between?)
Add a parameter ‘start_lookup_from’? But this way we’ll have to expose the container’s internals - it can not be a base interface (virtual function in TObject).
P.S.
After all you can easily write your own generic standalone functions, applying some transformations to any ROOT’s sequence with a predicate parameter etc.
P.P.S.
Examples:
[code]//______________________________________________________________________________
TObject *TList::FindObject(const TObject *obj) const
{
// Find an object in this list using the object’s IsEqual()
// member function. Requires a sequential scan till the object has
// been found. Returns 0 if object is not found.
// This method overrides the generic FindObject() of TCollection for
// efficiency reasons.
TObjLink *lnk = FirstLink();
while (lnk) {
TObject *ob = lnk->GetObject();
if (ob->IsEqual(obj)) return ob;//Here you do something instead of return and continue
lnk = lnk->Next();
}
return 0;
}[/code]
[code]//______________________________________________________________________________
TObject *TCollection::FindObject(const TObject *obj) const
{
// Find an object in this collection using the object’s IsEqual()
// member function. Requires a sequential scan till the object has
// been found. Returns 0 if object is not found.
// Typically this function is overridden by a more efficient version
// in concrete collection classes (e.g. THashTable).
TIter next(this);
TObject *ob;
while ((ob = next()))
if (ob->IsEqual(obj)) return ob;//Do not return, but ‘process’ this entry somehow and continue
return 0;
}[/code]
[code]//______________________________________________________________________________
TObject *THashTable::FindObject(const TObject *obj) const
{
// Find object using its hash value (returned by its Hash() member).
if (IsArgNull(“FindObject”, obj)) return 0;
Int_t slot = GetHashValue(obj);
if (fCont[slot]) return fCont[slot]->FindObject(obj);//This is essentially TList::FindObject
return 0;
}[/code]