Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the most elegant way to get a set of items by index from a collection?

Tags:

c#

Given

IList<int> indexes;
ICollection<T> collection;

What is the most elegant way to extract all T in collection based on the the indexes provided in indexes?

For example, if collection contained

"Brian", "Cleveland", "Joe", "Glenn", "Mort"

And indexes contained

1, 3

The return would be

"Cleveland," "Glenn"

Edit: Assume that indexes is always sorted ascending.

like image 881
Bob Avatar asked Jun 19 '09 14:06

Bob


People also ask

How do you find the index of a set?

To get the index of item in a JavaScript set, we can convert the set into an array and then use the array indexOf method. to create a set with the Set constructor. Then we spread the set s into an array with the spread operator. Next, we call indexOf on the array with the value we want to find the index for.

Does collection have an index?

An index can be defined on a Collection property (java. util. Collection implementation) or Array. Setting such an index means that each of the Collection's or Array's items is indexed.

Does set have index?

Unlike List and arrays, Set does NOT support indexes or positions of it's elements. Set supports Generics and we should use it whenever possible. Using Generics with Set will avoid ClassCastException at runtime. We can use Set interface implementations to maintain unique elements.


2 Answers

This assumes that the index sequence is a monotone ascending sequence of non-negative indices. The strategy is straightforward: for each index, bump up an enumerator on the collection to that point and yield the element.

public static IEnumerable<T> GetIndexedItems<T>(this IEnumerable<T> collection, IEnumerable<int> indices)
{
    int currentIndex = -1;
    using (var collectionEnum = collection.GetEnumerator())
    {
        foreach(int index in indices)
        {
            while (collectionEnum.MoveNext()) 
            {
                currentIndex += 1;
                if (currentIndex == index)
                {
                    yield return collectionEnum.Current;
                    break;
                }
            }
        }    
    }
}

Advantages of this solution over other solutions posted:

  • O(1) in extra storage -- some of these solutions are O(n) in space
  • O(n) in time -- some of these solutions are quadradic in time
  • works on any two sequences; does not require ICollection or IList.
  • only iterates the collection once; some solutions iterate the collection multiple times (to build a list out of it, for instance.)

Disadvantages:

  • harder to read
like image 163
Eric Lippert Avatar answered Oct 12 '22 18:10

Eric Lippert


Here's a faster version:

IEnumerable<T> ByIndices<T>(ICollection<T> data, IList<int> indices)
{
    int current = 0;
    foreach(var datum in data.Select((x, i) => new { Value = x, Index = i }))
    {
        if(datum.Index == indices[current])
        {
            yield return datum.Value;
            if(++current == indices.Count)
                yield break;
        }
    }
}
like image 33
mqp Avatar answered Oct 12 '22 20:10

mqp