用另一个列表更新一个列表所需的最少代码量是多少
本文关键字:列表 代码 多少 一个 更新 另一个 | 更新日期: 2023-09-27 17:48:51
假设我有一个列表:
IList<int> originalList = new List<int>();
originalList.add(1);
originalList.add(5);
originalList.add(10);
还有另一个列表。。。
IList<int> newList = new List<int>();
newList.add(1);
newList.add(5);
newList.add(7);
newList.add(11);
如何更新originalList以便:
- 如果int出现在newList中,请保持
- 如果int没有出现在newList中,请移除
- 将newList中尚未存在的任何int添加到originalList中
因此,制作originalList的内容:
{ 1, 5, 7, 11 }
我之所以这么问,是因为我有一件物品,里面有一群孩子。当用户更新此集合时,与其只是删除所有子项,然后插入他们的选择,我认为如果我只是对添加或删除的子项执行操作,而不是拆下整个集合,然后插入newList子项,就好像它们都是新的一样,会更有效率。
编辑-对不起-我写了一个可怕的标题。。。我应该写"最少的代码",而不是"高效的"。我想这让我得到了很多答案。他们都很棒。。。非常感谢。
originalList = newList;
或者,如果你喜欢它们是不同的列表:
originalList = new List<int>(newList);
但是,任何一种方式都可以满足你的需求。根据您的规则,更新后,originalList将与newList相同。
更新:我感谢大家对这个答案的支持,但仔细阅读这个问题后,我相信我的另一个答案(下面)是正确的。
如果您使用一些LINQ扩展方法,您可以在两行中完成:
originalList.RemoveAll(x => !newList.Contains(x));
originalList.AddRange(newList.Where(x => !originalList.Contains(x)));
这假设(和其他人的解决方案一样)您已经覆盖了原始对象中的Equals。但是,如果由于某种原因无法覆盖Equals,则可以创建如下的IEqualityOperator:
class EqualThingTester : IEqualityComparer<Thing>
{
public bool Equals(Thing x, Thing y)
{
return x.ParentID.Equals(y.ParentID);
}
public int GetHashCode(Thing obj)
{
return obj.ParentID.GetHashCode();
}
}
然后上面的行变成:
originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Where(x => !originalList.Contains(x, new EqualThingTester())));
如果你无论如何都要通过IEqualityOperator,你可以让第二行更短:
originalList.RemoveAll(x => !newList.Contains(x, new EqualThingTester()));
originalList.AddRange(newList.Except(originalList, new EqualThingTester()));
对不起,我在看到你的最后一段之前写了第一个回复。
for(int i = originalList.length-1; i >=0; --i)
{
if (!newList.Contains(originalList[i])
originalList.RemoveAt(i);
}
foreach(int n in newList)
{
if (!originaList.Contains(n))
originalList.Add(n);
}
如果您不担心最终的排序,Hashtable/HashSet可能是最快的。
LINQ解决方案:
originalList = new List<int>(
from x in newList
join y in originalList on x equals y into z
from y in z.DefaultIfEmpty()
select x);
我最初的想法是,你可以调用originalList.AddRange(newList),然后删除重复项,但我不确定这是否比清除列表并重新填充更有效。
List<int> firstList = new List<int>() {1, 2, 3, 4, 5};
List<int> secondList = new List<int>() {1, 3, 5, 7, 9};
List<int> newList = new List<int>();
foreach (int i in firstList)
{
newList.Add(i);
}
foreach (int i in secondList)
{
if (!newList.Contains(i))
{
newList.Add(i);
}
}
不是很干净,但它有效。
没有内置的方法可以做到这一点,我能想到的最接近的是DataTable处理新项目和已删除项目的方式。
@James Curran建议的只是用newList对象替换originalList对象。它将转储oldList,但保留变量(即指针仍在那里)。
无论如何,您应该考虑优化这段时间是否花费得当。将值从一个列表复制到下一个列表所花费的大部分运行时间,这可能是值得的。如果不是,而是你正在进行的一些过早的优化,你应该忽略它。
在开始优化之前,花时间打磨GUI或对应用程序进行概要分析是我的一大优势。
这是开发人员在编写UI以维护多对多数据库关系时遇到的常见问题。我不知道这有多有效,但我写了一个助手类来处理这种情况:
public class IEnumerableDiff<T>
{
private delegate bool Compare(T x, T y);
private List<T> _inXAndY;
private List<T> _inXNotY;
private List<T> _InYNotX;
/// <summary>
/// Compare two IEnumerables.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="compareKeys">True to compare objects by their keys using Data.GetObjectKey(); false to use object.Equals comparison.</param>
public IEnumerableDiff(IEnumerable<T> x, IEnumerable<T> y, bool compareKeys)
{
_inXAndY = new List<T>();
_inXNotY = new List<T>();
_InYNotX = new List<T>();
Compare comparer = null;
bool hit = false;
if (compareKeys)
{
comparer = CompareKeyEquality;
}
else
{
comparer = CompareObjectEquality;
}
foreach (T xItem in x)
{
hit = false;
foreach (T yItem in y)
{
if (comparer(xItem, yItem))
{
_inXAndY.Add(xItem);
hit = true;
break;
}
}
if (!hit)
{
_inXNotY.Add(xItem);
}
}
foreach (T yItem in y)
{
hit = false;
foreach (T xItem in x)
{
if (comparer(yItem, xItem))
{
hit = true;
break;
}
}
if (!hit)
{
_InYNotX.Add(yItem);
}
}
}
/// <summary>
/// Adds and removes items from the x (current) list so that the contents match the y (new) list.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="compareKeys"></param>
public static void SyncXList(IList<T> x, IList<T> y, bool compareKeys)
{
var diff = new IEnumerableDiff<T>(x, y, compareKeys);
foreach (T item in diff.InXNotY)
{
x.Remove(item);
}
foreach (T item in diff.InYNotX)
{
x.Add(item);
}
}
public IList<T> InXAndY
{
get { return _inXAndY; }
}
public IList<T> InXNotY
{
get { return _inXNotY; }
}
public IList<T> InYNotX
{
get { return _InYNotX; }
}
public bool ContainSameItems
{
get { return _inXNotY.Count == 0 && _InYNotX.Count == 0; }
}
private bool CompareObjectEquality(T x, T y)
{
return x.Equals(y);
}
private bool CompareKeyEquality(T x, T y)
{
object xKey = Data.GetObjectKey(x);
object yKey = Data.GetObjectKey(y);
return xKey.Equals(yKey);
}
}
如果您使用.Net 3.5
var List3 = List1.Intersect(List2);
创建一个包含两个列表的交集的新列表,我相信这就是你在这里拍摄的目的。