我有两个列表对象A和B,如下所示:
A=[
{item:1, value:"ex1"},
{item:2, value:"ex1"},
{item:3, value:"ex1"},
{item:4, value:"ex1"}]
B=[{item:1, value:"ex2"},
{item:4, value:"ex2"},
{item:2, value:"ex3"},
{item:5, value:"ex3"}]
如何使B具有与A相同的项目/值,并且仍然保留其已有项目的序列?
我希望B删除第5项,因为A没有,并将第3项添加到最后。
我不想克隆A,我想修改B变成A。
我想要的是:
当A没有物品时,删除B中的物品:item5
当A和B都拥有它们时更新B中的项目:item1,item2,item4
当A有它们时,将不存在的项目添加到B的结尾:item3
所以,结果应该是这样的:
B = [ {item:1, value:"ex1"},
{item:4, value:"ex1"},
{item:2, value:"ex1"},
{item:3, value:"ex1"} ]
Mycode :(这就是我现在拥有的)
foreach (myClass itm in A)
{
foreach (myClass fd in B)
{
if (itm.item == fd.item)
{
fd.value = itm.value;
}
}
}
答案 0 :(得分:1)
您可以编写一个扩展方法,通过迭代键并检查是否存在来合并列表。
static class ExtensionMethods
{
static public void MergeInto<TKey,TValue>(this Dictionary<TKey,TValue> rhs, Dictionary<TKey,TValue> lhs)
{
foreach (var key in rhs.Keys.Union(lhs.Keys).Distinct().ToList())
{
if (!rhs.ContainsKey(key))
{
lhs.Remove(key);
continue;
}
if (!lhs.ContainsKey(key))
{
lhs.Add(key, rhs[key]);
continue;
}
lhs[key] = rhs[key];
}
}
}
测试程序:
public class Program
{
public static Dictionary<int,string> A = new Dictionary<int,string>
{
{ 1,"ex1" },
{ 2,"EX2" },
{ 3,"ex3" },
};
public static Dictionary<int,string> B = new Dictionary<int,string>
{
{ 1,"ex1" },
{ 2,"ex2" },
{ 4,"ex4" }
};
public static void Main()
{
A.MergeInto(B);
foreach (var entry in B )
{
Console.WriteLine("{0}={1}", entry.Key, entry.Value);
}
}
}
输出:
1=ex1
2=EX2
3=ex3
答案 1 :(得分:1)
如果您只想保留B的实例,但要使其所有元素都匹配A,那么您可以这样做:
B.Clear();
B.AddRange(A);
如果您想保留订单,仍然可以使用上面的解决方案,但是您需要对传递给AddRange()
的列表进行排序。这只是一点点工作。
首先,创建一个查找表,告诉您Item项最初出现的顺序。通用c#Dictionary
使用哈希表作为键,因此最终会比扫描更有效反复列表。请注意,我们将B.Count
传递给构造函数,以便它只需要一次分配空间,而不是在增长时重复分配。
var orderBy = new Dictionary<int,int>(B.Count);
for (int i=0; i<B.Count; i++) orderBy.Add(B[i].Item, i);
现在我们使用我们的解决方案,对输入列表进行排序:
B.Clear();
B.AddRange
(
A.OrderBy( item => orderBy.GetValueOrFallback(item.Item, int.MaxValue) )
);
GetValueOrFallback
是Dictionary<,>
上的一种简单扩展方法,可以更轻松地处理可能存在或不存在的密钥。传入所需的密钥,如果找不到密钥则返回一个值。在我们的例子中,我们传递int.MaxValue
,以便将新项目附加到最后。
static public TValue GetValueOrFallback<TKey,TValue>(this Dictionary<TKey,TValue> This, TKey keyToFind, TValue fallbackValue)
{
TValue result;
return This.TryGetValue(keyToFind, out result) ? result : fallbackValue;
}
将所有这些与测试程序结合在一起:
public class MyClass
{
public int Item { get; set; }
public string Value { get; set; }
public override string ToString() { return Item.ToString() + "," + Value; }
}
static public class ExtensionMethods
{
static public TValue ValueOrFallback<TKey,TValue>(this Dictionary<TKey,TValue> This, TKey keyToFind, TValue fallbackValue)
{
TValue result;
return This.TryGetValue(keyToFind, out result) ? result : fallbackValue;
}
static public void MergeInto(this List<MyClass> mergeFrom, List<MyClass> mergeInto)
{
var orderBy = new Dictionary<int,int>(mergeFrom.Count);
for (int i=0; i<mergeInto.Count; i++) orderBy.Add(mergeInto[i].Item, i);
mergeInto.Clear();
mergeInto.AddRange
(
mergeFrom.OrderBy( item => orderBy.ValueOrFallback(item.Item, int.MaxValue) )
);
}
}
public class Program
{
public static List<MyClass> A = new List<MyClass>
{
new MyClass { Item = 2,Value = "EX2" },
new MyClass { Item = 3,Value = "ex3" },
new MyClass { Item = 1,Value = "ex1" }
};
public static List<MyClass> B = new List<MyClass>
{
new MyClass { Item = 1,Value = "ex1" },
new MyClass { Item = 2,Value = "ex2" },
new MyClass { Item = 4,Value = "ex3" },
};
public static void Main()
{
A.MergeInto(B);
foreach (var b in B) Console.WriteLine(b);
}
}
输出:
1,ex1
2,EX2
3,ex3
答案 2 :(得分:0)
这是您在问题中指定的内容。我测试了它并且它有效:
class myClass
{
public int item;
public string value;
//ctor:
public myClass(int item, string value) { this.item = item; this.value = value; }
}
static void updateList()
{
var listA = new List<myClass> { new myClass(1, "A1"), new myClass(2, "A2"), new myClass(3, "A3"), new myClass(4, "A4") };
var listB = new List<myClass> { new myClass(1, "B1"), new myClass(4, "B4"), new myClass(2, "B2"), new myClass(5, "B5") };
for (int i = 0; i < listB.Count; i++) //use index to be able to use RemoveAt which is faster
{
var b = listB[i];
var j = listA.FindIndex(x => x.item == b.item);
if (j >= 0) //A has this item, update its value
{
var v = listA[j].value;
if (b.value != v) b.value = v;
}
else //A does not have this item
{
listB.RemoveAt(i);
}
}
foreach (var a in listA)
{
//if (!listB.Contains(a)) listB.Add(a);
if (!listB.Any(b => b.item == a.item)) listB.Add(a);
}
}
答案 3 :(得分:-1)
你可以做类似的事情:
var listA = new List<int> { 1, 3, 5 };
var listB = new List<int> { 1, 4, 3 };
//Removes items in B that aren't in A.
//This will remove 4, leaving the sequence of B as 1,3
listB.RemoveAll(x => !listA.Contains(x));
//Gets items in A that aren't in B
//This will return the number 5
var items = listA.Where(y => !listB.Any(x => x == y));
//Add the items in A that aren't in B to the end of the list
//This adds 5 to the end of the list
foreach(var item in items)
{
listB.Add(item);
}
//List B should be 1,3,5
Console.WriteLine(listB);