.NET oferuje ogólny kontener listy, którego wydajność jest prawie identyczna (zobacz pytanie Wydajność tablic a listy). Jednak są one zupełnie inne w inicjalizacji.
Tablice są bardzo łatwe do zainicjowania z wartością domyślną iz definicji mają już określony rozmiar:
string[] Ar = new string[10];
Co pozwala na bezpieczne przypisywanie losowych przedmiotów, powiedzmy:
Ar[5]="hello";
z listą rzeczy są trudniejsze. Widzę dwa sposoby wykonania tej samej inicjalizacji, z których żaden nie jest tym, co nazwałbyś eleganckim:
List<string> L = new List<string>(10);
for (int i=0;i<10;i++) L.Add(null);
lub
string[] Ar = new string[10];
List<string> L = new List<string>(Ar);
Jaki byłby czystszy sposób?
EDYCJA: dotychczasowe odpowiedzi odnoszą się do pojemności, co jest czymś innym niż wstępne wypełnienie listy. Na przykład na właśnie utworzonej liście o pojemności 10 nie można tego zrobićL[2]="somevalue"
EDYCJA 2: Ludzie zastanawiają się, dlaczego chcę używać list w ten sposób, skoro nie jest to sposób, w jaki mają być używane. Widzę dwa powody:
Można by całkiem przekonująco argumentować, że listy są tablicami „nowej generacji”, dodającymi elastyczności prawie bez żadnych kar. Dlatego należy ich używać domyślnie. Zwracam uwagę, że mogą nie być tak łatwe do zainicjowania.
To, co obecnie piszę, to klasa bazowa oferująca domyślną funkcjonalność jako część większego frameworka. W domyślnej funkcjonalności, którą oferuję, rozmiar listy jest znany w zaawansowanym i dlatego mogłem użyć tablicy. Chcę jednak zaoferować każdej klasie bazowej możliwość jej dynamicznego rozszerzenia, dlatego wybieram listę.
List
nie zastępujeArray
. Rozwiązują wyraźnie oddzielne problemy. Jeśli chcesz mieć stały rozmiar, potrzebujeszArray
. Jeśli używaszList
, robisz to źle.Odpowiedzi:
Nie mogę powiedzieć, że potrzebuję tego bardzo często - czy możesz podać więcej szczegółów, dlaczego tego chcesz? Prawdopodobnie umieściłbym to jako metodę statyczną w klasie pomocniczej:
Państwo mogli używać
Enumerable.Repeat(default(T), count).ToList()
, ale to byłoby nieefektywne ze względu na bufor zmiany rozmiaru.Zauważ, że jeśli
T
jest typem referencyjnym, będzie przechowywaćcount
kopie referencji przekazanej dlavalue
parametru - więc wszystkie będą odnosić się do tego samego obiektu. To może, ale nie musi być tym, czego chcesz, w zależności od twojego przypadku użycia.EDYCJA: Jak zauważono w komentarzach, jeśli chcesz, możesz
Repeated
użyć pętli do wypełnienia listy. To też byłoby nieco szybsze. Osobiście uważam, że kod jestRepeat
bardziej opisowy i podejrzewam, że w prawdziwym świecie różnica w wydajności byłaby nieistotna, ale przebieg może się różnić.źródło
Enumerable.Repeat(...).ToArray()
, który nie jest tym, jak go używam.Enumerable.Repeat()
w następujący sposób (zaimplementowanyPair
tak jak odpowiednik w C ++):Enumerable.Repeat( new Pair<int,int>(int.MaxValue,-1), costs.Count)
zauważając efekt uboczny, żeList
był pełen odwołań do kopii pojedynczego obiektu. Zmiana elementu jakmyList[i].First = 1
zmieniła każdy element w całościList
. Znalezienie tego błędu zajęło mi wiele godzin. Czy znacie jakieś rozwiązanie tego problemu (oprócz zwykłego używania wspólnej pętli i używania.Add(new Pair...)
?źródło
L
po prostu ponownie wykorzysta pamięć w stanie, wstring[10]
jakim jest (magazyn zapasowy list jest również tablicą), czy też przydzieli nową własną pamięć, a następnie skopiuje zawartośćstring[10]
?string[10]
automatycznie zbiera elementy bezużyteczne, jeśliL
wybierze późniejszą trasę.Użyj konstruktora, który przyjmuje jako argument int („capacity”):
EDYCJA: Dodam, że zgadzam się z Frederikiem. Używasz Listy w sposób, który jest sprzeczny z całym rozumowaniem stojącym za jej użyciem.
EDYCJA2:
Dlaczego ktoś miałby znać rozmiar listy zawierającej wszystkie wartości null? Gdyby na liście nie było żadnych rzeczywistych wartości, spodziewałbym się, że długość będzie równa 0. W każdym razie fakt, że jest on gęsty, dowodzi, że jest to sprzeczne z przeznaczeniem tej klasy.
źródło
new List<string>()
jeśli chodzi o problem . Dobra robota z otrzymaniem tylu pozytywnych głosów :)list[index] = obj;
i użyć innych funkcji list.Najpierw utwórz tablicę z żądaną liczbą elementów, a następnie przekonwertuj ją na listę.
źródło
Dlaczego używasz listy, jeśli chcesz ją zainicjować ze stałą wartością? Rozumiem, że - ze względu na wydajność - chcesz nadać jej początkową pojemność, ale czy nie jest jedną z zalet listy w porównaniu ze zwykłą tablicą, którą może powiększać w razie potrzeby?
Kiedy to robisz:
Tworzysz listę o pojemności 100 liczb całkowitych. Oznacza to, że Twoja lista nie będzie musiała „rosnąć”, dopóki nie dodasz 101 pozycji. Podstawowa tablica listy zostanie zainicjowana z długością 100.
źródło
Inicjowanie zawartości takiej listy nie jest tak naprawdę tym, do czego służą listy. Listy są przeznaczone do przechowywania obiektów. Jeśli chcesz odwzorować określone liczby na określone obiekty, rozważ użycie struktury par klucz-wartość, takiej jak tabela skrótów lub słownik, zamiast listy.
źródło
Wydaje się, że podkreślasz potrzebę pozycyjnego powiązania z danymi, więc czy tablica asocjacyjna nie byłaby bardziej odpowiednia?
źródło
Jeśli chcesz zainicjować listę N elementami o stałej wartości:
źródło
Możesz użyć Linq, aby sprytnie zainicjować listę z wartością domyślną. (Podobnie jak odpowiedź Davida B. )
Idź o krok dalej i zainicjuj każdy ciąg odrębnymi wartościami „ciąg 1”, „ciąg 2”, „ciąg 3” itd .:
źródło
źródło
Zaakceptowana odpowiedź (ta z zielonym haczykiem) zawiera problem.
Problem:
Zalecam zmianę powyższej linii, aby wykonać kopię obiektu. Istnieje wiele różnych artykułów na ten temat:
Jeśli chcesz zainicjować każdy element na liście za pomocą domyślnego konstruktora, a nie NULL, dodaj następującą metodę:
źródło
Uwaga dotycząca IList: MSDN IList Uwagi : "Implementacje IList dzielą się na trzy kategorie: tylko do odczytu, o stałym rozmiarze i o zmiennym rozmiarze. (...). Ogólną wersję tego interfejsu można znaleźć w
System.Collections.Generic.IList<T>
."IList<T>
NIE dziedziczy poIList
(aleList<T>
implementuje obaIList<T>
iIList
), ale zawsze ma zmienny rozmiar . Od .NET 4.5 mamy również,IReadOnlyList<T>
ale AFAIK, nie ma ogólnej listy o stałym rozmiarze, która byłaby tym, czego szukasz.źródło
To jest próbka, której użyłem do mojego testu jednostkowego. Stworzyłem listę obiektów klasy. Następnie użyłem forloop, aby dodać liczbę obiektów „X”, których oczekuję od usługi. W ten sposób możesz dodać / zainicjować listę dla dowolnego rozmiaru.
Mam nadzieję, że pomogłem wam.
źródło
Trochę późno, ale pierwsze zaproponowane przez ciebie rozwiązanie wydaje mi się o wiele czystsze: nie przydziela się pamięci dwukrotnie. Nawet constrcutor listy musi przejść przez tablicę, aby ją skopiować; nawet z góry nie wie, że w środku są tylko elementy zerowe.
1. - przydziel N - pętla N Koszt: 1 * przydziel (N) + N * loop_iteration
2. - przydziel N - przydziel N + pętlę () Koszt: 2 * przydziel (N) + N * loop_iteration
Jednak alokacja listy, pętle mogą być szybsze, ponieważ List jest klasą wbudowaną, ale C # jest skompilowany w jit, więc ...
źródło