รายการ <T> รับประกันคำสั่งแทรกหรือไม่


238

บอกว่าฉันมี 3 สายในรายการ (เช่น "1", "2", "3")

จากนั้นฉันต้องการเรียงลำดับใหม่ให้วาง "2" ในตำแหน่ง 1 (เช่น "2", "1", "3")

ฉันใช้รหัสนี้ (การตั้งค่า indexToMoveTo เป็น 1):

listInstance.Remove(itemToMove);
listInstance.Insert(indexToMoveTo, itemToMove);

ดูเหมือนว่าจะใช้งานได้ แต่บางครั้งฉันก็ได้ผลลัพธ์ที่แปลก บางครั้งคำสั่งซื้อไม่ถูกต้องหรือรายการจากรายการจะถูกลบ!

ความคิดใด ๆ ไม่List<T>เพื่อรับประกัน?

ที่เกี่ยวข้อง:

List <T> รับประกันว่าจะมีการส่งคืนสินค้าตามลำดับที่ถูกเพิ่มเข้าไปหรือไม่?


3
สิ่งนี้ไม่เป็นจริงดังที่กล่าวไว้ที่นี่: stackoverflow.com/a/1790318/696517
jrmgx

คำตอบ:


311

List<>ระดับไม่สั่งซื้อการรับประกัน - สิ่งที่จะถูกเก็บรักษาไว้ในรายชื่อในลำดับที่คุณเพิ่มพวกเขารวมทั้งรายการที่ซ้ำกันเว้นแต่ว่าคุณได้เรียงลำดับรายการ

อ้างอิงจาก MSDN:

... รายการ "แสดงรายการของวัตถุที่สามารถเข้าถึงได้โดยดัชนี "

ค่าดัชนีต้องเชื่อถือได้เพื่อให้สิ่งนี้ถูกต้อง ดังนั้นรับประกันการสั่งซื้อ

คุณอาจจะได้รับผลที่แปลกจากรหัสของคุณถ้าคุณกำลังจะย้ายรายการต่อไปในรายการที่เป็นของคุณRemove()จะย้ายทั้งหมดของรายการอื่น ๆ Insert()ลงที่เดียวก่อนที่จะเรียกร้องให้

คุณสามารถต้มโค้ดให้เล็กลงพอที่จะโพสต์ได้หรือไม่


63
สำหรับ googler ในอนาคตนี่คือคำพูดที่ถูกต้องจาก MSDN (bolding mine) สำหรับList (T). เพิ่ม วัตถุที่จะถูกเพิ่มลงในตอนท้ายของรายการ <T> ค่าสามารถเป็นโมฆะสำหรับประเภทการอ้างอิง
aolszowka

4
มีคำพูด / การอ้างอิงที่ชัดเจนมากขึ้นที่เราจะได้รับจาก Microsoft หรือข้อกำหนด C # เกี่ยวกับเรื่องนี้หรือไม่? คำพูดของ @ @ aolszowka ดูเหมือนว่าจะแนะนำว่ามันยังคงคำสั่งแทรก แต่ในทางเทคนิครายการสามารถสั่งซื้อคอลเลกชันใหม่ได้ตลอดเวลาหลังจากที่รายการถูกเพิ่มและคำสั่งนั้นจะยังคงถูกต้อง ฉันไม่ต้องการที่จะได้รับจู้จี้จุกจิกเกี่ยวกับเรื่องนี้ แต่ถ้าผู้จัดการหรือ QA ทำให้ฉันปกป้องตำแหน่งนี้จริง ๆ ฉันจะไม่รู้สึกมั่นใจมากนักกับคำพูดนั้น
tehDorf

4
ฉันสามารถคิดถึงวิธีที่มีประโยชน์สองวิธีในการขอรับการยืนยัน ก่อนอื่นให้อ่านแหล่งที่มาและทำให้พอใจ ประการที่สองตรวจสอบความหมายของชนิดข้อมูลนามธรรมListในตำราวิทยาศาสตร์คอมพิวเตอร์ที่ดีใด ๆ เช่นเดียวกับQueueและStacka Listคือโครงสร้างข้อมูลที่กำหนดชัดเจนคาดเดาได้และเข้าใจได้ดีหากการใช้. NET แตกต่างกัน (หรือหากมีการเปลี่ยนแปลง) ซอฟต์แวร์จำนวนมากจะพัง
Bevan

@tehDorf สิ่งที่ฉันทำ (ถ้ามีการอภิปราย) คือ: "หากการสั่งซื้อมีผลต่อการทำงานของวิธีการ / อัลกอริทึมของคุณคุณควรสั่งรายการอย่างชัดเจนหรือให้ API ของคุณใช้อินเทอร์เฟซ / คลาสที่เหมาะสมเช่น IOrderedEnumerable หรือ SortedList มิฉะนั้นคุณไม่ควรพึ่งพาการใช้งานเฉพาะอย่างเพื่อทำพฤติกรรมบางอย่างเว้นแต่จะมีการระบุไว้อย่างชัดเจน "คุณต้องระมัดระวังเกี่ยวกับการเรียงลำดับรายการ <T> อย่างชัดเจนเนื่องจากการใช้งานของพวกเขาใช้การเรียงลำดับที่ไม่เสถียร
aolszowka

1
@achuthakrishnan พวกเขาเป็นประเด็นแยกต่างหาก รายการรับประกันว่ารายการจะถูกเก็บไว้ในลำดับที่พวกเขาจะถูกเพิ่มลงในรายการ เมื่อคุณใช้Where()วิธีLINQ เพื่อกรองรายการคุณต้องพึ่งพาการนำไปใช้งานเพื่อพิจารณารายการต่างๆตามลำดับ มันเกิดขึ้นที่มันทำ (ดูReferencesource.microsoft.com/System.Core/System/Linq/… ) แต่สิ่งนี้ไม่ได้บันทึกไว้ใน MSDN ฉันขอแนะนำให้ใช้emp.LastOrDefault(x => x.empDept = 'abc')เป็นเอกสารประกอบของLastOrDefault()ไม่ระบุว่าจะรักษาลำดับของรายการ
Bevan

36

นี่คือ 4 รายการพร้อมกับดัชนี

0  1  2  3
K  C  A  E

คุณต้องการย้าย K ไปที่ระหว่าง A และ E - คุณอาจคิดว่าตำแหน่งที่ 3 คุณต้องระวังเกี่ยวกับการจัดทำดัชนีของคุณที่นี่เพราะหลังจากการลบดัชนีทั้งหมดจะได้รับการอัปเดต

ดังนั้นคุณลบรายการ 0 ออกก่อน

0  1  2
C  A  E

จากนั้นคุณแทรกที่ 3

0  1  2  3
C  A  E  K

เพื่อให้ได้ผลลัพธ์ที่ถูกต้องคุณควรใช้ดัชนี 2 เพื่อให้สิ่งที่สอดคล้องกันคุณจะต้องส่งไปที่ (indexToMoveTo-1) if indexToMoveTo > indexToMoveเช่น

bool moveUp = (listInstance.IndexOf(itemToMoveTo) > indexToMove);
listInstance.Remove(itemToMove);
listInstance.Insert(indexToMoveTo, moveUp ? (itemToMoveTo - 1) : itemToMoveTo);

สิ่งนี้อาจเกี่ยวข้องกับปัญหาของคุณ ทราบว่ารหัสของฉันยังไม่ได้ทดสอบ!

แก้ไข : หรือมิSortฉะนั้นคุณสามารถใช้เครื่องมือเปรียบเทียบแบบกำหนดเอง ( IComparer) หากสิ่งนั้นใช้ได้กับสถานการณ์ของคุณ


ไม่ได้อ่านคำตอบของเบแวนอย่างรอบคอบเพียงพอฉันแค่คลุมดินที่เขามีอยู่
Joel Goodwin

9
ใช่ แต่คุณได้อธิบายอย่างละเอียดและให้ตัวอย่างของคำตอบของ Bevan เช่นเดียวกับรหัสวิธีแก้ไขปัญหาบางอย่างดังนั้นคำตอบของคุณจะไม่ซ้ำกันและฉันโหวตให้คุณ
Jason S

9

ดังที่ Bevan กล่าว แต่โปรดจำไว้ว่า list-index นั้นใช้ 0 หากคุณต้องการย้ายองค์ประกอบไปไว้ข้างหน้าของรายการคุณจะต้องแทรกไว้ที่ดัชนี 0 (ไม่ใช่ 1 ดังที่แสดงในตัวอย่างของคุณ)


1

นี่คือรหัสที่ฉันมีสำหรับการย้ายรายการลงในที่เดียวในรายการ:

if (this.folderImages.SelectedIndex > -1 && this.folderImages.SelectedIndex < this.folderImages.Items.Count - 1)
{
    string imageName = this.folderImages.SelectedItem as string;
    int index = this.folderImages.SelectedIndex;

    this.folderImages.Items.RemoveAt(index);
    this.folderImages.Items.Insert(index + 1, imageName);
    this.folderImages.SelectedIndex = index + 1;
 }

และนี่เป็นการย้ายที่เดียว:

if (this.folderImages.SelectedIndex > 0)
{
    string imageName = this.folderImages.SelectedItem as string;
    int index = this.folderImages.SelectedIndex;

    this.folderImages.Items.RemoveAt(index);
    this.folderImages.Items.Insert(index - 1, imageName);
    this.folderImages.SelectedIndex = index - 1;
}

folderImagesเป็นListBoxของหลักสูตรดังนั้นรายการจึงเป็น a ListBox.ObjectCollectionไม่ใช่ไม่ใช่List<T>แต่สืบทอดมาจากรายการIListดังนั้นจึงควรมีพฤติกรรมเหมือนกัน สิ่งนี้ช่วยได้ไหม?

แน่นอนว่ารายการเก่าจะใช้ได้ก็ต่อเมื่อรายการที่เลือกไม่ใช่รายการสุดท้ายในรายการและรายการสุดท้ายหากรายการที่เลือกไม่ใช่รายการแรก


1

หากคุณจะเปลี่ยนลำดับของการดำเนินการคุณจะหลีกเลี่ยงพฤติกรรมที่แปลก: ขั้นแรกแทรกค่าไปยังตำแหน่งที่ถูกต้องในรายการแล้วลบออกจากตำแหน่งแรกของเขา ตรวจสอบให้แน่ใจว่าคุณลบดัชนีของเขาเพราะถ้าคุณจะลบมันโดยอ้างอิงคุณอาจลบทั้งสอง ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.