【问题标题】:Move multiple items in a list移动列表中的多个项目
【发布时间】:2012-11-08 15:45:44
【问题描述】:

我有一个实现 IEnumerable<T> 的列表类。
Type T 是一个复杂的类,以字符串成员作为唯一标识符。但仅以 int 作为元素类型来解释就足够了。

我想将多个项目向左移动一步。
示例:
原始列表:0、1、2、34、5
现在所有粗体项目 (0,3,4) 都应该移到左边(尽可能远)。
结果列表:0, 1, 3, 4, 2, 5

有没有好的算法来做到这一点?也许只是使用 LINQ。

编辑:欢迎List<T> 列表的答案。我的班级有类似的方法。 (感谢 TylerOhlsen 的提示。)
Edit2:一个选定的项目不应传递另一个选定的项目。

【问题讨论】:

  • 这不是真正的“尽可能”,你的意思是左移一位吗?
  • @lc。尽可能向左一步(例如0不能移动)
  • @lc。元素 0 未向左移动。这就是我的意思是“尽可能”。如果项目 1 也被标记为要移动(在项目 0 旁边),那么这个移动也将被忽略。
  • @Rawling 不会产生这样的结果:0、1、3、2、4、5?您希望列表看起来像这样 0, 3, 4, 1, 2, 5 还是 0, 1, 3, 4, 2, 5(您提供的那个)。在后一个中,为什么 1 不移动?

标签: c#


【解决方案1】:

这看起来可行:

public static IEnumerable<T> MoveSelectedLeft<T>(
    this IEnumerable<T> source,
    IEnumerable<int> indicesToMove /* must be in order! */)
{
    using (var itm = indicesToMove.GetEnumerator())
    {
        bool hasNextToMove = itm.MoveNext();
        int nextToMove = hasNextToMove ? itm.Current : -1;

        bool canMoveYet = false;
        T held = default(T);
        int currentIndex = 0;

        foreach (T t in source)
        {
            if (hasNextToMove && nextToMove == currentIndex)
            {
                hasNextToMove = itm.MoveNext();
                nextToMove = hasNextToMove ? itm.Current : -1;
                yield return t;
            }
            else
            {
                if (!canMoveYet)
                {
                    canMoveYet = true;
                }
                else
                {
                    yield return held;
                }
                held = t;
            }

            currentIndex++;
        }

        if (canMoveYet)
            yield return held;
    }
}

称为

foreach (int i in new[] { 0,1,2,3,4,5 }.MoveSelectedLeft(new[] { 0,3,4 }))
{
    Console.WriteLine(i);
}

【讨论】:

    【解决方案2】:

    我没有想出使用 Linq 的好方法,但这里有一个简单的循环算法。如果你能想出一个排序功能,那就更好了。或者你可以看看 Linq Zip 方法。

    IList<int> myList = new List<int>(new[] {0, 1, 2, 3, 4, 5});
    IList<int> moveLeftList = new List<int>(new[] {0, 1, 3, 4});
    
    //Go through the original list in order and remove
    // all items from the move left list until you reach
    // the first item that is not going to be moved left.
    //Items removed are already as far left as they can be
    // so they do not need to be moved left and can therefore
    // be safely removed from the list to be moved.
    foreach (int item in myList)
    {
        int index = moveLeftList.IndexOf(item);
    
        if (index >= 0)
            moveLeftList.RemoveAt(index);
        else
            break;
    }
    
    foreach (int item in moveLeftList)
    {
        int index = myList.IndexOf(item);
    
        //Dont move left if it is the first item in the list or it is not in the list
        if (index <= 0)
            continue;
    
        //Swap with this item with the one to its left
        myList.RemoveAt(index);
        myList.Insert(index-1, item);
    }
    

    【讨论】:

    • 如果您的moveLeftList 同时包含01,这会交换它们吗?
    • @TylerOhlsen 一个选定的项目不应传递另一个选定的项目。
    • 编辑现在处理这种特殊情况,因为这只发生在列表中的第一个和后续项目。
    【解决方案3】:

    这里是一个算法的描述。将元素直接存储到元素组的左侧(在本例中为2)在`temp 变量中。

    从最左边的元素开始,将元素向左 1×1 移动。

    temp 变量放在组现在所在位置的右侧。

    如果您使用的是链表,它会更好。您只需从其所在位置删除2,并将其插入组的右侧。

    【讨论】:

      【解决方案4】:

      您应该为此使用“排序”功能并提供自定义比较器。

      看看this example

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-24
        • 1970-01-01
        • 1970-01-01
        • 2013-10-27
        • 1970-01-01
        相关资源
        最近更新 更多