List <T>는 게재 신청서를 보장합니까?


238

목록에 3 개의 문자열이 있다고 가정합니다 (예 : "1", "2", "3").

그런 다음 위치 1에 "2"를 배치하도록 순서를 바꾸고 싶습니다 (예 : "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에 따르면 :

... List " index 로 액세스 할 수있는 강력한 형식의 개체 목록을 나타냅니다 ."

이것이 정확하려면 인덱스 값을 신뢰할 수 있어야합니다. 따라서 주문이 보장됩니다.

Remove()호출하기 전에 다른 모든 항목을 한 곳 아래로 이동 하므로 목록에서 나중에 항목을 이동하면 코드에서 이상한 결과를 얻을 수 있습니다 Insert().

코드를 게시하기에 충분히 작은 것으로 끓일 수 있습니까?


63
미래의 Google 직원에게는 MSDN (볼딩 광산)에서 List (T)에 대한 정확한 인용문이 있습니다 .Add <T> 끝에 추가 할 객체 입니다. 참조 유형의 경우 값이 널일 수 있습니다.
aolszowka

4
이에 대한 Microsoft 또는 C # 사양에서 얻을 수있는보다 명확한 견적 / 참조가 있습니까? @ aolszowka의 인용문은 확실히 삽입 순서를 유지한다고 제안하는 것처럼 보이지만 기술적으로 List는 항목이 추가 된 후 언제든지 컬렉션을 재정렬 할 수 있으며 그 진술은 여전히 ​​유효합니다. 나는 그것에 대해 까다로워지고 싶지 않지만 관리자 나 QA가 실제로이 입장을 변호하게했다면 그 인용에 대해 확신이 들지 않을 것입니다.
tehDorf

4
확인을 얻는 두 가지 유용한 방법을 생각할 수 있습니다. 먼저 소스를 읽고 만족하십시오. 둘째, List좋은 컴퓨터 과학 교과서에서 추상 데이터 유형의 정의를 확인하십시오 . Queueand와 마찬가지로 Stacka List는 잘 정의되고 예측 가능하며 잘 이해 된 데이터 구조입니다. .NET 구현이 달라 지거나 변경되는 경우 많은 소프트웨어가 손상 될 수 있습니다.
Bevan

@tehDorf 나의 취향은 (논리가 논의되는 경우) : "주문이 메소드 / 알고리즘의 작동에 영향을 미치는 경우 목록을 명시 적으로 주문하거나 API가 IOrderedEnumerable 또는 SortedList, 그렇지 않으면 특정 구현이 확실하게 명시 적으로 언급되지 않는 한 특정 방식으로 작동하지 않아야합니다. "또한 구현에서 불안정한 정렬을 사용하므로 List <T>를 명시 적으로 정렬하는 데주의해야합니다.
aolszowka

1
@achuthakrishnan 그들은 별도의 문제입니다. 목록은 항목이 목록에 추가 된 순서대로 유지되도록합니다. LINQ Where()메서드를 사용하여 목록을 필터링하면 순서에 따라 항목을 순서대로 고려하는 구현에 의존합니다. 그것이 발생 하지만 ( 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

올바른 결과를 얻으려면, 당신은 (indexToMoveTo-1)로 보내야합니다 상황이 일관성을 유지하기 위해 사용되는 인덱스 2를해야한다 if indexToMoveTo > indexToMove, 예를 들어,

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

문제와 관련이있을 수 있습니다. 내 코드는 테스트되지 않았습니다.

편집 : 또는 상황에 해당하는 경우 Sort사용자 지정 비교기 ( IComparer)를 사용할 수도 있습니다.


베 반의 대답을 충분히주의 깊게 읽지 않았고, 나는 그가 가진 근거를 막 설명했다.
Joel Goodwin 2016 년

9
예, 그러나 솔루션 코드뿐만 아니라 Bevan의 답변에 대한 예를 자세히 설명 했으므로 귀하의 답변은 혼란스럽지 않으며 귀하에게 투표했습니다.
Jason S

9

Bevan이 말했듯이 명단 인덱스는 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;
}

folderImagesA는 ListBox리스트가 그래서 물론이 ListBox.ObjectCollection아닌을 List<T>하지만,이 상속 않습니다 IList이 동일하게 동작해야하므로. 도움이 되나요?

물론 전자는 선택한 항목이 목록의 마지막 항목이 아닌 경우에만 작동하고 후자는 선택한 항목이 첫 번째 항목이 아닌 경우에만 작동합니다.


1

작업 순서를 변경하면 이상한 동작을 피할 수 있습니다. 먼저 목록의 올바른 위치에 값을 삽입 한 다음 첫 번째 위치에서 삭제하십시오. 참조로 삭제하면 둘 다 삭제할 ​​수 있으므로 색인으로 삭제해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.