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

后端 未结 14 2023
梦如初夏
梦如初夏 2020-12-13 04:57

Given

IList indexes;
ICollection collection;

What is the most elegant way to extract all T in

相关标签:
14条回答
  • 2020-12-13 05:50

    It seems that the most efficient way would be to use a Dictionary<int,T> instead of a Collection<T>. You can still keep a list of indexes you want to use in the IList<int>.

    0 讨论(0)
  • 2020-12-13 05:54

    As I understand it, an ICollection may not necessarily have any order which is why there isn't an extremely elegant solution to access things by index. You many want to consider using a dictionary or list to store the data in the collection.

    The best way I can think of is to iterate through the collection while keeping track of what index you are on. Then check if the indexes list contains that index. If so, return that element.

    0 讨论(0)
  • 2020-12-13 05:56

    Not elegant, but efficient - make sure indexes are sorted ...

    ICollection<T> selected = new Collection<T>();
    var indexesIndex = 0;
    var collectionIndex = 0;
    foreach( var item in collection )
    {
        if( indexes[indexesIndex] != collectionIndex++ )
        {
            continue;
        }
        selected.Add( item );
        if( ++indexesIndex == indexes.Count )
        {
            break;
        }
    }
    
    0 讨论(0)
  • 2020-12-13 05:58

    Not sure how elegant this is, but here you go.

    Since ICollection<> doesn't give you indexing I just used IEnumerable<>, and since I didn't need the index on the IList<> I used IEnumerable<> there too.

    public static IEnumerable<T> IndexedLookup<T>(
        IEnumerable<int> indexes, IEnumerable<T> items)
    {
        using (var indexesEnum = indexes.GetEnumerator())
        using (var itemsEnum = items.GetEnumerator())
        {
            int currentIndex = -1;
            while (indexesEnum.MoveNext())
            {
                while (currentIndex != indexesEnum.Current)
                {
                    if (!itemsEnum.MoveNext())
                        yield break;
                    currentIndex++;
                }
    
                yield return itemsEnum.Current;
            }
        }
    }
    

    EDIT: Just noticed my solution is similar to Erics.

    0 讨论(0)
  • 2020-12-13 06:01

    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
    0 讨论(0)
  • 2020-12-13 06:01

    As a proper answer :

    var col = new []{"a","b","c"};
    var ints = new []{0,2};
    var set = new HashSet<int>(ints);
    
    var result = col.Where((item,index) => set.Contains(index));
    

    A usual with IList.Contains or Enumerable.Contains, don't do lookups in lists if you don't know how many indexes there will be in the collection. Or you'll go the O(n^2) way the hard way. If you want to be on the safe side, you should use a intermediary Lookup/Dictionary/Hashset and test on this collection and not on the vanilla list (linear search is not good for you)

    0 讨论(0)
提交回复
热议问题