如何统计列表中被用户主动上下移动的项的数量
如何统计列表中被用户主动上下移动的项的数量
咱们先把需求掰碎了看:你要统计的是用户亲手操作过的项,那些因为被其他项挤来挤去而被动改变位置的项不算;而且同一个项被用户来回移动多次,只要最终没回到原始位置,就算1个,如果绕了一圈又回去了,就不算。
之前你用的对比原始/最终索引的方法,会把所有位置变化的项都算进去,这肯定会把被动移动的项(比如被D挤到前面的E)误统计进来,显然不符合要求。
那怎么解决呢?核心思路是在用户操作的时候就跟踪哪些项是被主动操作的,而不是事后从两个状态反推——毕竟有些情况从最终状态根本分不清谁是主动的(比如D和E交换,你没法知道是用户动了D还是E)。而且这个方案完全不用修改你的MyItem类,刚好符合你的需求。
具体实现步骤
1. 初始化一个跟踪集合
用HashSet<MyItem>来存被用户主动操作过的项,因为MyItem是引用类型,集合会自动去重(同一个项被操作多次也只会存一次):
HashSet<MyItem> userInitiatedMoves = new HashSet<MyItem>();
2. 在用户执行移动操作时记录
不管用户是点击“上移”还是“下移”某个项,只要触发了移动逻辑,就把这个项添加到集合里:
// 处理用户上移操作的方法 void MoveItemUp(MyItem item) { int currentIndex = ListMyItems.IndexOf(item); if (currentIndex > 0) { // 执行移动逻辑 ListMyItems.RemoveAt(currentIndex); ListMyItems.Insert(currentIndex - 1, item); // 记录用户主动操作了这个项 userInitiatedMoves.Add(item); } } // 处理用户下移操作的方法 void MoveItemDown(MyItem item) { int currentIndex = ListMyItems.IndexOf(item); if (currentIndex < ListMyItems.Count - 1) { ListMyItems.RemoveAt(currentIndex); ListMyItems.Insert(currentIndex + 1, item); // 记录用户主动操作了这个项 userInitiatedMoves.Add(item); } }
3. 最终统计符合条件的项
从跟踪集合里筛选出最终位置和原始位置不同的项,数量就是你要的结果:
// 先把原始列表的索引存到字典里,方便快速查找 var originalIndexMap = ListMyItemsOriginal .Select((item, index) => new { item, index }) .ToDictionary(x => x.item, x => x.index); int count = userInitiatedMoves .Count(item => originalIndexMap.TryGetValue(item, out int originalIndex) && ListMyItems.IndexOf(item) != originalIndex);
为什么这个方案靠谱?
- 只统计用户亲手操作过的项,被动被挤的项根本不会进入跟踪集合,完美排除误统计;
- 同一个项被操作多次,集合里只会存一次,符合“多次移动算一个”的规则;
- 最后筛选掉那些操作后回到原始位置的项,满足“回到原位不算”的要求;
- 完全不用修改
MyItem类,贴合你的需求。
验证你的示例
咱们用你给的例子测试一下:
- D下移一次:跟踪集合里只有D,最终D的位置和原始不同,count=1 ✔️
- D下移两次:集合里还是只有D,最终位置和原始不同,count=1 ✔️
- E下移一次 + D下移一次:集合里有E和D,两者最终位置都和原始不同,count=2 ✔️
关于仅靠原始/最终状态反推的说明
说实话,很难做到100%准确。比如如果用户先移动D下移一次,再移动E上移一次,最终结果是D和E交换,这时候从原始和最终状态看,两者位置都变了,但你没法区分哪个是主动操作的。所以在操作过程中跟踪是最可靠的办法。
内容来源于stack exchange
相关产品推荐
相关产品推荐

