Interleave different length lists, elimating duplicates, and preserve order

后端 未结 6 2284
青春惊慌失措
青春惊慌失措 2021-02-11 22:00

I have two lists, let\'s say:

keys1 = [\'A\', \'B\', \'C\', \'D\', \'E\',           \'H\', \'I\']
keys2 = [\'A\', \'B\',           \'E\', \'F\', \'G\', \'H\',            


        
6条回答
  •  执笔经年
    2021-02-11 22:57

    Here's a C# solution I came up with -- using an extension method -- for the case where the two lists might not contain the same type of elements, so it takes a compare method and a selector method (that returns an object of the target type given the source object). In this case, the first list ("me") is modified to contain the final result, but it could be modified to create a separate list.

    public static class ListExtensions
    {
        /// 
        /// Merges two sorted lists containing potentially different types of objects, resulting in a single
        /// sorted list of objects of type T with no duplicates.
        /// 
        public static void MergeOrderedList(this List me, IReadOnlyList other, Func compare = null, Func selectT = null)
        {
            if (other == null)
                throw new ArgumentNullException(nameof(other));
            if (compare == null)
            {
                if (typeof(TMe).GetInterfaces().Any(i => i == typeof(IComparable)))
                {
                    compare = (a, b) => ((IComparable)a).CompareTo(b);
                }
                else
                {
                    throw new ArgumentNullException(nameof(compare),
                        "A comparison method must be supplied if no default comparison exists.");
                }
            }
    
            if (selectT == null)
                if (typeof(TMe).IsAssignableFrom(typeof(TOther)))
                {
                    selectT = o => (TMe)(o as object);
                }
                else
                {
                    throw new ArgumentNullException(nameof(selectT),
                        $"A selection method must be supplied if the items in the other list cannot be assigned to the type of the items in \"{nameof(me)}\"");
                }
    
            if (me.Count == 0)
            {
                me.AddRange(other.Select(selectT));
                return;
            }
    
            for (int o = 0, m = 0; o < other.Count; o++)
            {
                var currentOther = other[o];
                while (compare(me[m], currentOther) < 0 && ++m < me.Count) {}
    
                if (m == me.Count)
                {
                    me.AddRange(other.Skip(o).Select(selectT));
                    break;
                }
    
                if (compare(me[m], currentOther) != 0)
                    me.Insert(m, selectT(currentOther));
            }
        }
    }
    

    Note: I did write unit tests for this, so it's solid.

提交回复
热议问题