জেনেরিক তালিকা - তালিকার মধ্যে একটি আইটেম সরানো


155

সুতরাং আমি একটি জেনেরিক তালিকা, এবং একটি oldIndexএবং একটি newIndexমান আছে।

আমি আইটেমটি সরাতে চান oldIndexকরতে, newIndex... কেবল যতটা সম্ভব।

কোনও পরামর্শ?

বিঃদ্রঃ

আইটেমটি অপসারণের আগে(newIndex - 1) এবং আইটেমগুলির মধ্যে শেষ হওয়া উচিত ।newIndex


1
আপনি যে উত্তরটি পছন্দ করেছেন তা আপনার পরিবর্তন করা উচিত। newIndex--আপনি যা বলেছিলেন তার আচরণের সাথে তার পরিণতি হয় না।
মিরাল

1
@ মিরাল - আপনি কি মনে করেন যে উত্তরটি গ্রহণযোগ্য হওয়া উচিত?
রিচার্ড ইভ 11

4
jpierson আছে। এটি সেই বস্তুটির ফলস্বরূপ যা সরানোর পরে নতুন ইনডেক্সে যাওয়ার আগে ওল্ডআইডেক্সে ব্যবহৃত হত। এটি সর্বনিম্ন অবাক করা আচরণ (এবং যখন আমি কিছু ড্রাগ'আরড্রপ পুনঃক্রমের কোড লিখছিলাম তখন আমার এটির প্রয়োজন ছিল)। মঞ্জুর তিনি কথা বলা হচ্ছে ObservableCollectionএবং একটি জেনেরিক না List<T>, কিন্তু এটা তুচ্ছ ব্যাপার কেবল পদ্ধতি কল অদলবদল করার একই ফলাফল পেতে।
মিরাল

অনুরোধ করা (এবং এই উত্তরটিতে সঠিকভাবে প্রয়োগ করা ) আচরণ আইটেমগুলির মধ্যে আইটেমটি সরানোর জন্য [newIndex - 1]এবং [newIndex]অবিচ্ছিন্ন নয়। Move(1, 3); Move(3, 1);প্রাথমিক অবস্থায় তালিকাকে ফিরিয়ে দেয় না। ইতিমধ্যে এই উত্তরে প্রদত্ত ObservableCollectionএবং উল্লিখিত বিভিন্ন আচরণ রয়েছে যা অবিচ্ছিন্ন
লাইটম্যান

উত্তর:


138

আমি জানি আপনি "জেনেরিক তালিকা" বলেছেন তবে আপনি তালিকা (টি) শ্রেণিটি ব্যবহার করার দরকার ছিল তা নির্দিষ্ট করেননি তাই এখানে অন্যরকম কিছু করার শট দেওয়া আছে।

ObservableCollection (টি) বর্গ টি সরান পদ্ধতি আছে যা আপনি ঠিক কি চান।

public void Move(int oldIndex, int newIndex)

এটির নীচে এটি মূলত এইভাবে প্রয়োগ করা হয়।

T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);

সুতরাং যেহেতু আপনি দেখতে পাচ্ছেন যে অদলবদল পদ্ধতি যা অন্যরা পরামর্শ দিয়েছে তা হ'ল পর্যবেক্ষণযোগ্য সংগ্রহটি তার নিজস্ব সরানো পদ্ধতিতে কী করে।

আপডেট ২০১২-১২-২০: আপনি নেটফেক্সে মুভ এবং মুভ আইটেম পদ্ধতির সোর্স কোডটি এখনই নিজের জন্য রিফ্লেক্টর / আইএলএসপি ব্যবহার না করে নিজের জন্য দেখতে পারেন যেহেতু। নেট ওপেন সোর্স।


28
আমি অবাক হয়েছি কেন কেন এই তালিকা <টি> তেও প্রয়োগ করা হচ্ছে না, এই বিষয়ে কিছু আলোকপাত করার জন্য যে কেউ?
Andreas

জেনেরিক তালিকা এবং একটি তালিকা (টি) শ্রেণীর মধ্যে পার্থক্য কী? আমি ভেবেছিলাম সেগুলি একই ছিল :(
বিকেএসপুরজন

একটি "জেনেরিক তালিকা" কোন (টি) .NET মধ্যে তালিকা বা ডাটা স্ট্রাকচার মত সংগ্রহের প্রকার যা ObservableCollection অন্তর্ভুক্ত হতে পারে বা অন্য ক্লাসের যা বাস্তবায়ন করিতে পারিবে মানে হতে পারে listy যেমন IList / ICollection / IEnumerable ইন্টারফেস।
jpierson

6
কেউ ব্যাখ্যা করতে পারেন, দয়া করে কেন কোনও গন্তব্য সূচী শিফট নেই (যদি এটি উত্স সূচকের চেয়ে বড় হয়)?
ভ্লাদিয়াস

@ ভ্লাদিয়াস আমি বিশ্বাস করি যে ধারণাটি এই যে নির্দিষ্ট করা নতুন ইনডেক্স মানটি পছন্দসই সূচকটি নির্দিষ্ট করে দেয় যে আইটেমটি সরানোর পরে হওয়া উচিত এবং যেহেতু একটি সন্নিবেশ ব্যবহার করা হচ্ছে সেখানে সামঞ্জস্য করার কোনও কারণ নেই। যদি নিউ ইনডেক্স মূল সূচকটির সাথে তুলনামূলকভাবে একটি অবস্থান ছিল তবে আমার ধারণা অন্য গল্প হবে তবে এটি কীভাবে কাজ করে না।
jpierson

129
var item = list[oldIndex];

list.RemoveAt(oldIndex);

if (newIndex > oldIndex) newIndex--; 
// the actual index could have shifted due to the removal

list.Insert(newIndex, item);

9
তালিকায় আইটেমের দুটি অনুলিপি থাকলে আপনার সমাধানটি ভেঙে যায়, যার মধ্যে একটি ওলিআইডেক্সের আগে ঘটে। আপনি সঠিকটি পেয়েছেন তা নিশ্চিত করার জন্য আপনার সরানোআউট ব্যবহার করা উচিত।
অ্যারন মইনপা ই

6
আসলে, স্নিগ্ধ প্রান্তের কেস
গ্যারি শাটলার

1
@ গ্যারিশুটলার আমি দেখতে পাচ্ছি না যে আমরা যদি কোনও আইটেম সরিয়ে এবং তারপরে সন্নিবেশ করানো হয় তবে সূচকটি কীভাবে বদল হতে পারে। newIndexপ্রকৃতপক্ষে হ্রাস করা আমার পরীক্ষাটি বিরতি দেয় (নীচে আমার উত্তর দেখুন)।
বেন ফস্টার 10

1
দ্রষ্টব্য: থ্রেড-সুরক্ষা যদি গুরুত্বপূর্ণ হয় তবে এগুলি সমস্ত lockবিবৃতিতে থাকা উচিত ।
rory.ap

1
আমি এটি ব্যবহার করব না কারণ এটি বিভিন্ন কারণে বিভ্রান্তিকর। তালিকায় একটি পদ্ধতি মুভ (ওল্ডআইএনডেক্স, নিউইনডেক্স) সংজ্ঞায়িত করা এবং মুভ (15,25) এবং তারপরে মুভ (25,15) কল করা একটি পরিচয় নয় তবে অদলবদল। এছাড়াও মুভ (15,25) আইটেমটিকে সূচক 24 এ স্থানান্তরিত করে 25 এ নয় যা আমি আশা করব। অদলবদল ছাড়াও টেম্প = আইটেম [ওল্ডইন্ডেক্স] প্রয়োগ করা যেতে পারে; আইটেম [oldindex] = আইটেম [newindex]; আইটেম [newindex] = টেম্প; যা বড় অ্যারেতে আরও দক্ষ বলে মনে হচ্ছে। এছাড়াও মুভ (0,0) এবং সরানো (0,1) একই হবে যা বিজোড়। এবং সরান (0, গণনা -1) আইটেমটি শেষ পর্যন্ত সরিয়ে দেয় না।
ওয়াউটার 21

12

আমি জানি এই প্রশ্নটি পুরানো তবে আমি জাভাস্ক্রিপ্ট কোডের এই প্রতিক্রিয়াটিকে C # তে মানিয়ে নিয়েছি । আশা করি এটা সাহায্য করবে

 public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{

    // exit if possitions are equal or outside array
    if ((oldIndex == newIndex) || (0 > oldIndex) || (oldIndex >= list.Count) || (0 > newIndex) ||
        (newIndex >= list.Count)) return;
    // local variables
    var i = 0;
    T tmp = list[oldIndex];
    // move element down and shift other elements up
    if (oldIndex < newIndex)
    {
        for (i = oldIndex; i < newIndex; i++)
        {
            list[i] = list[i + 1];
        }
    }
        // move element up and shift other elements down
    else
    {
        for (i = oldIndex; i > newIndex; i--)
        {
            list[i] = list[i - 1];
        }
    }
    // put element from position 1 to destination
    list[newIndex] = tmp;
}

9

তালিকা <T>। সরান () এবং তালিকা <T>। সরানোআউট () সরানো হচ্ছে না এমন আইটেমটি ফিরিয়ে দেবেন না।

সুতরাং আপনাকে এটি ব্যবহার করতে হবে:

var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);

5

আইটেম ঢোকান বর্তমানে oldIndexএ হতে newIndexএবং তারপর মূল উদাহরণস্বরূপ মুছে ফেলুন।

list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);

আপনাকে অ্যাকাউন্টে নিতে হবে যে আইটেমটি আপনি মুছে ফেলতে চান তার সূচক সন্নিবেশের কারণে পরিবর্তিত হতে পারে।


1
Serোকানোর আগে আপনার সরানো উচিত ... আপনার আদেশের ফলে তালিকার বরাদ্দ হতে পারে।
জিম বাল্টার

4

আমি তালিকায় আইটেমগুলি সরানোর জন্য একটি এক্সটেনশন পদ্ধতি তৈরি করেছি।

আমরা যদি বিদ্যমান আইটেমটিকে তালিকার একটি বিদ্যমান সূচী অবস্থানে নিয়ে যাচ্ছি তবে আমরা একটি বিদ্যমান আইটেমটি সরিয়ে নিলে একটি সূচক স্থানান্তরিত হওয়া উচিত নয় ।

@ অলিভার নীচে উল্লেখ করে এমন প্রান্তের কেস (তালিকার শেষে একটি আইটেম সরিয়ে নেওয়া) আসলে পরীক্ষাগুলি ব্যর্থ হওয়ার কারণ হতে পারে, তবে এটি নকশা দ্বারা। তালিকার শেষে একটি নতুন আইটেম সন্নিবেশ করতে আমরা কেবল কল করব List<T>.Add। ব্যর্থ list.Move(predicate, list.Count) হওয়া উচিত কারণ সরানোর আগে এই সূচক অবস্থানটি বিদ্যমান নেই।

যাই হোক না কেন, আমি দুটি অতিরিক্ত এক্সটেনশন পদ্ধতি তৈরি করেছি MoveToEndএবং MoveToBeginningযার উত্স এখানে পাওয়া যাবে

/// <summary>
/// Extension methods for <see cref="System.Collections.Generic.List{T}"/>
/// </summary>
public static class ListExtensions
{
    /// <summary>
    /// Moves the item matching the <paramref name="itemSelector"/> to the <paramref name="newIndex"/> in a list.
    /// </summary>
    public static void Move<T>(this List<T> list, Predicate<T> itemSelector, int newIndex)
    {
        Ensure.Argument.NotNull(list, "list");
        Ensure.Argument.NotNull(itemSelector, "itemSelector");
        Ensure.Argument.Is(newIndex >= 0, "New index must be greater than or equal to zero.");

        var currentIndex = list.FindIndex(itemSelector);
        Ensure.That<ArgumentException>(currentIndex >= 0, "No item was found that matches the specified selector.");

        // Copy the current item
        var item = list[currentIndex];

        // Remove the item
        list.RemoveAt(currentIndex);

        // Finally add the item at the new index
        list.Insert(newIndex, item);
    }
}

[Subject(typeof(ListExtensions), "Move")]
public class List_Move
{
    static List<int> list;

    public class When_no_matching_item_is_found
    {
        static Exception exception;

        Establish ctx = () => {
            list = new List<int>();
        };

        Because of = ()
            => exception = Catch.Exception(() => list.Move(x => x == 10, 10));

        It Should_throw_an_exception = ()
            => exception.ShouldBeOfType<ArgumentException>();
    }

    public class When_new_index_is_higher
    {
        Establish ctx = () => {
            list = new List<int> { 1, 2, 3, 4, 5 };
        };

        Because of = ()
            => list.Move(x => x == 3, 4); // move 3 to end of list (index 4)

        It Should_be_moved_to_the_specified_index = () =>
            {
                list[0].ShouldEqual(1);
                list[1].ShouldEqual(2);
                list[2].ShouldEqual(4);
                list[3].ShouldEqual(5);
                list[4].ShouldEqual(3);
            };
    }

    public class When_new_index_is_lower
    {
        Establish ctx = () => {
            list = new List<int> { 1, 2, 3, 4, 5 };
        };

        Because of = ()
            => list.Move(x => x == 4, 0); // move 4 to beginning of list (index 0)

        It Should_be_moved_to_the_specified_index = () =>
        {
            list[0].ShouldEqual(4);
            list[1].ShouldEqual(1);
            list[2].ShouldEqual(2);
            list[3].ShouldEqual(3);
            list[4].ShouldEqual(5);
        };
    }
}

Ensure.Argumentসংজ্ঞায়িত কোথায় ?
অলিভার

1
সাধারণভাবে List<T>আপনি Insert(list.Count, element)তালিকার শেষে কিছু রাখতে কল করতে পারেন । সুতরাং আপনার When_new_index_is_higherকল করা উচিত list.Move(x => x == 3, 5)যা আসলে ব্যর্থ।
অলিভার

3
@ সাধারণভাবে অলিভার List<T>আমি কেবল একটি তালিকার শেষে .Addএকটি নতুন আইটেম সন্নিবেশ করানোর জন্য কল করব । স্বতন্ত্র আইটেমগুলি সরানোর সময় আমরা কখনই সূচকের মূল আকার বাড়াতে পারি না কারণ আমরা কেবলমাত্র একটি আইটেম সরিয়ে ফেলা হয় এবং এটিকে পুনরায় সন্নিবিষ্ট করছি। আপনি যদি আমার উত্তরের লিঙ্কটি ক্লিক করেন তবে আপনি কোডটি খুঁজে পাবেন Ensure.Argument
বেন ফস্টার

আপনার সমাধানটি প্রত্যাশা করে যে গন্তব্য সূচকটি একটি অবস্থান, দুটি উপাদানের মধ্যে নয়। যদিও এটি কিছু ব্যবহারের ক্ষেত্রে ভাল কাজ করে তবে অন্যের পক্ষে এটি কার্যকর হয় না। এছাড়াও, আপনার পদক্ষেপটি শেষ দিকে চলে যাওয়া সমর্থন করে না (যেমন অলিভার দ্বারা উল্লিখিত) তবে আপনার কোডটিতে আপনি এই সীমাবদ্ধতাটি কোনও জায়গায় নির্দেশ করেন না। এটিও বিপরীতমুখী, যদি আমার 20 টি উপাদান সহ একটি তালিকা থাকে এবং উপাদানটি 10 ​​টি শেষ পর্যন্ত স্থানান্তর করতে চান তবে আমি মুভ পদ্ধতিটি হ্যান্ডেল করার প্রত্যাশা করব, বরং তারপরে অবজেক্টের রেফারেন্সটি সংরক্ষণ করার জন্য, তালিকাটি থেকে বস্তুটিকে সরিয়ে ফেলতে হবে এবং অবজেক্টটি যুক্ত করুন।
পরীক্ষিত

1
@ ট্রাইপড আসলে আপনি যদি আমার উত্তরটি পড়ে থাকেন তবে কোনও আইটেমিকে তালিকার শেষে / শুরুতে সরিয়ে নেওয়া সমর্থনযোগ্য। আপনি এখানে চশমা দেখতে পারেন । হ্যাঁ আমার কোডটি সূচকে তালিকার মধ্যে একটি বৈধ (বিদ্যমান) অবস্থান হিসাবে প্রত্যাশা করে। আমরা চলন্ত আইটেম, তাদের ঢোকাতে না।
বেন ফস্টার

1

আমি আশা করি:

// Makes sure item is at newIndex after the operation
T item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);

... বা:

// Makes sure relative ordering of newIndex is preserved after the operation, 
// meaning that the item may actually be inserted at newIndex - 1 
T item = list[oldIndex];
list.RemoveAt(oldIndex);
newIndex = (newIndex > oldIndex ? newIndex - 1, newIndex)
list.Insert(newIndex, item);

... কৌতুকটি করবে, তবে আমার কাছে এই মেশিনে চেক করার জন্য ভিএস নেই।


1
@ গ্যারিশুটলার এটি পরিস্থিতির উপর নির্ভর করে। যদি আপনার ইন্টারফেস ব্যবহারকারীকে তালিকার তালিকাতে অবস্থান নির্দিষ্ট করতে দেয় তবে তারা বিভ্রান্ত হয়ে পড়বে যখন তারা আইটেম 15 কে 20 এ স্থানান্তরিত করতে বলবে, তবে পরিবর্তে এটি 19 এ চলে যাবে your যদি আপনার ইন্টারফেসটি ব্যবহারকারীকে অন্যের মধ্যে কোনও আইটেম টেনে আনতে দেয় তালিকার পরে এটি হ্রাস করতে হবে newIndexযদি এটি পরে থাকে oldIndex
পরীক্ষিত

-1

সহজ উপায়:

list[newIndex] = list[oldIndex];
list.RemoveAt(oldIndex);

সম্পাদনা

প্রশ্নটি খুব স্পষ্ট নয় ... যেহেতু list[newIndex]আইটেমটি কোথায় যায় সেদিকে আমরা খেয়াল রাখি না বলে আমি মনে করি এটি করার সহজতম উপায়টি নীচে (এক্সটেনশন পদ্ধতির সাথে বা ছাড়াই):

    public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
    {
        T aux = list[newIndex];
        list[newIndex] = list[oldIndex];
        list[oldIndex] = aux;
    }

এই সমাধানটি দ্রুততম কারণ এটি তালিকার সন্নিবেশ / অপসারণগুলি জড়িত করে না।


4
এটি আইটেমটি নতুন ইনডেক্সে ওভাররাইট করবে, sertোকানো হবে না।
গ্যারি শাটলার

@ গ্যারি কি শেষ ফলাফলটি একই হতে চলেছে না?
ওজগুর ওসিতিটক

4
না, আপনি নতুন ইনডেক্সে মান হারাবেন যা আপনি inোকালে যদি তা ঘটবে না।
গ্যারি শাটলার

-2

আরও সহজ ছেলেরা কেবল এটি করে

    public void MoveUp(object item,List Concepts){

        int ind = Concepts.IndexOf(item.ToString());

        if (ind != 0)
        {
            Concepts.RemoveAt(ind);
            Concepts.Insert(ind-1,item.ToString());
            obtenernombres();
            NotifyPropertyChanged("Concepts");
        }}

মুভডাউন দিয়ে একই করুন তবে "যদি (ইন্ড!


-3

এভাবেই আমি একটি সরানো উপাদান এক্সটেনশন পদ্ধতি প্রয়োগ করেছি। এটি উপাদানগুলির জন্য আগে / পরে এবং চূড়ান্ত দিকে সরানো পরিচালনা করে।

public static void MoveElement<T>(this IList<T> list, int fromIndex, int toIndex)
{
  if (!fromIndex.InRange(0, list.Count - 1))
  {
    throw new ArgumentException("From index is invalid");
  }
  if (!toIndex.InRange(0, list.Count - 1))
  {
    throw new ArgumentException("To index is invalid");
  }

  if (fromIndex == toIndex) return;

  var element = list[fromIndex];

  if (fromIndex > toIndex)
  {
    list.RemoveAt(fromIndex);
    list.Insert(toIndex, element);
  }
  else
  {
    list.Insert(toIndex + 1, element);
    list.RemoveAt(fromIndex);
  }
}

2
এটি ফ্রান্সিসকো থেকে উত্তরের একটি সদৃশ।
nivs1978
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.