Fastest way to find common items across multiple lists in C#

后端 未结 11 1832

Given the following:

List> optionLists;

what would be a quick way to determine the subset of Option objects that a

相关标签:
11条回答
  • 2021-01-19 02:59

    Ok, this will find the list of Option objects that have a Value appearing in every list.

    var x = from list in optionLists
            from option in list
            where optionLists.All(l => l.Any(o => o.Value == option.Value))
            orderby option.Value
            select option;
    

    It doesn't do a "distinct" select so it'll return multiple Option objects, some of them with the same Value.

    0 讨论(0)
  • 2021-01-19 03:03

    I don't have the performance stats, but if you don't want to roll your own method, various collections libraries have a 'Set' or 'Set(T)' object that offer the usual set procedures. (listed in the order I would use them).

    1. IESI Collections (literally just Set classes)
    2. PowerCollections (not updated in a while)
    3. C5 (never personally used)
    0 讨论(0)
  • 2021-01-19 03:03
    /// <summary>
        /// The method FindCommonItems, returns a list of all the COMMON ITEMS in the lists contained in the listOfLists.
        /// The method expects lists containing NO DUPLICATE ITEMS.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="allSets"></param>
        /// <returns></returns>
        public static List<T> FindCommonItems<T>(IEnumerable<List<T>> allSets)
        {
            Dictionary<T, int> map = new Dictionary<T, int>();
            int listCount = 0; // Number of lists.
            foreach (IEnumerable<T> currentSet in allSets)
            {
                int itemsCount = currentSet.ToList().Count;
                HashSet<T> uniqueItems = new HashSet<T>();
                bool duplicateItemEncountered = false;
                listCount++;
                foreach (T item in currentSet)
                {
                    if (!uniqueItems.Add(item))
                    {
                        duplicateItemEncountered = true;
                    }                        
                    if (map.ContainsKey(item))
                    {
                        map[item]++;
                    } 
                    else
                    {
                        map.Add(item, 1);
                    }
                }
                if (duplicateItemEncountered)
                {
                    uniqueItems.Clear();
                    List<T> duplicateItems = new List<T>();
                    StringBuilder currentSetItems = new StringBuilder();
                    List<T> currentSetAsList = new List<T>(currentSet);
                    for (int i = 0; i < itemsCount; i++)
                    {
                        T currentItem = currentSetAsList[i];
                        if (!uniqueItems.Add(currentItem))
                        {
                            duplicateItems.Add(currentItem);
                        }
                        currentSetItems.Append(currentItem);
                        if (i < itemsCount - 1)
                        {
                            currentSetItems.Append(", ");
                        }
                    }
                    StringBuilder duplicateItemsNamesEnumeration = new StringBuilder();
                    int j = 0;
                    foreach (T item in duplicateItems)
                    {
                        duplicateItemsNamesEnumeration.Append(item.ToString());
                        if (j < uniqueItems.Count - 1)
                        {
                            duplicateItemsNamesEnumeration.Append(", ");
                        }
                    }
                    throw new Exception("The list " + currentSetItems.ToString() + " contains the following duplicate items: " + duplicateItemsNamesEnumeration.ToString());
                }
            }
            List<T> result= new List<T>();
            foreach (KeyValuePair<T, int> itemAndItsCount in map)
            {
                if (itemAndItsCount.Value == listCount) // Items whose occurrence count is equal to the number of lists are common to all the lists.
                {
                    result.Add(itemAndItsCount.Key);
                }
            }
    
            return result;
        }
    
    0 讨论(0)
  • 2021-01-19 03:06

    You can do this by counting occurrences of all items in all lists - those items whose occurrence count is equal to the number of lists, are common to all lists:

        static List<T> FindCommon<T>(IEnumerable<List<T>> lists)
        {
            Dictionary<T, int> map = new Dictionary<T, int>();
            int listCount = 0; // number of lists
    
            foreach (IEnumerable<T> list in lists)
            {
                listCount++;
                foreach (T item in list)
                {
                    // Item encountered, increment count
                    int currCount;
                    if (!map.TryGetValue(item, out currCount))
                        currCount = 0;
    
                    currCount++;
                    map[item] = currCount;
                }
            }
    
            List<T> result= new List<T>();
            foreach (KeyValuePair<T,int> kvp in map)
            {
                // Items whose occurrence count is equal to the number of lists are common to all the lists
                if (kvp.Value == listCount)
                    result.Add(kvp.Key);
            }
    
            return result;
        }
    
    0 讨论(0)
  • 2021-01-19 03:06

    After searching the 'net and not really coming up with something I liked (or that worked), I slept on it and came up with this. My SearchResult is similar to your Option. It has an EmployeeId in it and that's the thing I need to be common across lists. I return all records that have an EmployeeId in every list. It's not fancy, but it's simple and easy to understand, just what I like. For small lists (my case) it should perform just fine—and anyone can understand it!

    private List<SearchResult> GetFinalSearchResults(IEnumerable<IEnumerable<SearchResult>> lists)
    {
        Dictionary<int, SearchResult> oldList = new Dictionary<int, SearchResult>();
        Dictionary<int, SearchResult> newList = new Dictionary<int, SearchResult>();
    
        oldList = lists.First().ToDictionary(x => x.EmployeeId, x => x);
    
        foreach (List<SearchResult> list in lists.Skip(1))
        {
            foreach (SearchResult emp in list)
            {
                if (oldList.Keys.Contains(emp.EmployeeId))
                {
                    newList.Add(emp.EmployeeId, emp);
                }
            }
    
            oldList = new Dictionary<int, SearchResult>(newList);
            newList.Clear();
        }
    
        return oldList.Values.ToList();
    }
    
    0 讨论(0)
提交回复
热议问题