Adicionar novo item na matriz existente em c # .net


134

Como adicionar um novo item na matriz de string existente em C # .net?

Eu preciso preservar os dados existentes.

Respostas:


121

Eu usaria uma lista se você precisar de uma matriz de tamanho dinâmico:

List<string> ls = new List<string>();
ls.Add("Hello");

27
E, se necessário, fazer ls.ToArray () no final
Narayana

2
Usar outro mecânico que não seja solicitado na pergunta não é uma resposta.
user11909

@ user2190035: Não tenho certeza de onde você tirou essa idéia, e as 111 pessoas que votaram positivamente não concordariam com você. Se você souber uma maneira melhor de expandir uma matriz, então, publique-a. Duvido que sua realocação e cópia manual sejam melhores do que usar uma lista. Às vezes a resposta é "não faça isso".
21419 Ed Ed

@ EdS.A pergunta era: como adicionar um item a uma matriz de strings existente , mas essa resposta não possui uma matriz, em vez disso, cria uma nova lista <>. No meu aplicativo, não posso alterar o tipo para List <>, portanto, tenho que redimensionar uma matriz (fazendo uma cópia ...). A resposta de Ali Ersöz me ajudou.
user11909

@ user2190035: IEnumerable <T> .ToArray (). Eu escrevo C # todos os dias e nunca tive que redimensionar uma matriz como essa.
Ed

100

Isso poderia ser uma solução;

Array.Resize(ref array, newsize);
array[newsize - 1] = "newvalue"

Mas para uma matriz de tamanho dinâmico, prefiro a lista também.


@ Konrad, isso certamente preservará os dados na matriz.
Ali Ersöz 30/10/08

1
isso não é adequado por mais de alguns instantes. porque a função 'Redimensionar' tem um desempenho enorme. bug por uma ou duas vezes, isso é muito bom.
ad

53

Usando LINQ:

arr = (arr ?? Enumerable.Empty<string>()).Concat(new[] { newitem }).ToArray();

Eu gosto de usar isso, pois é uma linha única e muito conveniente para incorporar uma instrução switch, uma instrução if simples ou passar como argumento.

EDITAR:

Algumas pessoas não gostam, new[] { newitem }porque cria uma matriz pequena e temporária de um item. Aqui está uma versão usando Enumerable.Repeatque não requer a criação de nenhum objeto (pelo menos não na superfície - os iteradores do .NET provavelmente criam vários objetos da máquina de estado sob a tabela).

arr = (arr ?? Enumerable.Empty<string>()).Concat(Enumerable.Repeat(newitem,1)).ToArray();

E se você tiver certeza de que a matriz nunca nulldeve começar, pode simplificá-la para:

arr.Concat(Enumerable.Repeat(newitem,1)).ToArray();

Observe que se você deseja adicionar itens a uma coleção ordenada, Listprovavelmente é a estrutura de dados desejada, não uma matriz para começar.


1
Muito bom +1. Eu tenho um código semelhante como um método de extensão genérico. Eu incluí o código nesta resposta: stackoverflow.com/a/11035286/673545
dblood:

Isso é muito útil, pois ele procurava "como acrescentar a uma matriz em uma linha de código em c #" - espero que este comentário seja suficiente para encontrá-lo novamente na próxima vez.
Gary

28

Pergunta muito antiga, mas ainda queria adicionar isso.

Se você está procurando uma linha, pode usar o código abaixo. Ele combina o construtor da lista que aceita uma enumerável e a sintaxe do inicializador "novo" (desde que a pergunta foi levantada).

myArray = new List<string>(myArray) { "add this" }.ToArray();

27

Arrays em C # são imutáveis , por exemplo string[], int[]. Isso significa que você não pode redimensioná-los. Você precisa criar uma nova matriz.

Aqui está o código para Array.Resize :

public static void Resize<T>(ref T[] array, int newSize)
{
    if (newSize < 0)
    {
        throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    T[] sourceArray = array;
    if (sourceArray == null)
    {
        array = new T[newSize];
    }
    else if (sourceArray.Length != newSize)
    {
        T[] destinationArray = new T[newSize];
        Copy(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
        array = destinationArray;
    }
}

Como você pode ver, ele cria uma nova matriz com o novo tamanho, copia o conteúdo da matriz de origem e define a referência para a nova matriz. A dica para isso é a palavra-chave ref para o primeiro parâmetro.

Existem listas que podem alocar dinamicamente novos slots para novos itens. Isto é, por exemplo, Lista <T> . Eles contêm matrizes imutáveis ​​e as redimensionam quando necessário (a Lista <T> não é uma implementação de lista vinculada!). ArrayList é a mesma coisa sem Genéricos (com matriz de objetos ).

LinkedList <T> é uma implementação real de lista vinculada. Infelizmente, você pode adicionar apenas elementos LinkListNode <T> à lista, portanto, você deve agrupar seus próprios elementos de lista nesse tipo de nó. Eu acho que seu uso é incomum.


Eu acho que você ter significado Array.Copy
user123456

2
Apenas responder que fornece algumas informações para porque não é possível e não apenas de sugerir a utilização de uma lista ...
Gilad Verde

Eu acredito que Aray.Resizepode redimensionar uma matriz sem perder seu conteúdo. docs.microsoft.com/en-us/dotnet/api/…
AbdelAziz AbdelLatef

25
 Array.Resize(ref youur_array_name, your_array_name.Length + 1);
 your_array_name[your_array_name.Length - 1] = "new item";

7

Você pode expandir a resposta fornecida por @Stephen Chung usando sua lógica baseada em LINQ para criar um método de extensão usando um tipo genérico.

public static class CollectionHelper
{
    public static IEnumerable<T> Add<T>(this IEnumerable<T> sequence, T item)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(new[] { item });
    }

    public static T[] AddRangeToArray<T>(this T[] sequence, T[] items)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(items).ToArray();
    }

    public static T[] AddToArray<T>(this T[] sequence, T item)
    {
        return Add(sequence, item).ToArray();
    }

}

Você pode chamá-lo diretamente na matriz assim.

    public void AddToArray(string[] options)
    {
        // Add one item
        options = options.AddToArray("New Item");

        // Add a 
        options = options.AddRangeToArray(new string[] { "one", "two", "three" });

        // Do stuff...
    }

É certo que o método AddRangeToArray () parece um pouco exagerado, pois você tem a mesma funcionalidade do Concat (), mas dessa forma o código final pode "trabalhar" diretamente com a matriz, em oposição a isso:

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();

Obrigado, isso foi muito útil, eu adicionei uma opção para remover um item (espero que esteja tudo bem com você).
precisa

@TalSegal, de nada, meu prazer. Use o código como achar melhor!
dblood

6

É melhor manter o tamanho imutável e fixo do Array.

você pode simular Addpor Extension MethodeIEnumerable.Concat()

public static class ArrayExtensions
    {
        public static string[] Add(this string[] array, string item)
        {
            return array.Concat(new[] {item}).ToArray();
        }
    }

5

se você trabalha muito com matrizes e não lista por algum motivo, esse método genérico de retorno digitado genérico Addpode ajudar

    public static T[] Add<T>(T[] array, T item)
    {
        T[] returnarray = new T[array.Length + 1];
        for (int i = 0; i < array.Length; i++)
        {
            returnarray[i] = array[i];
        }
        returnarray[array.Length] = item;
        return returnarray;
    }

4

Todas as respostas propostas fazem o mesmo que dizem que gostariam de evitar, criando uma nova matriz e adicionando uma nova entrada apenas com mais sobrecarga perdida. LINQ não é mágico, a lista de T é uma matriz com um espaço de buffer com algum espaço extra para evitar o redimensionamento da matriz interna quando itens são adicionados.

Todas as abstrações precisam resolver o mesmo problema, criar uma matriz sem slots vazios que contenham todos os valores e os retornem.

Se você precisar da flexibilidade e criar uma lista grande o suficiente para passar, faça isso. caso contrário, use uma matriz e compartilhe esse objeto seguro para threads. Além disso, o novo Span ajuda a compartilhar dados sem precisar copiar as listas.

Para responder à pergunta:

Array.Resize(ref myArray, myArray.Length + 1);
data[myArray.Length - 1] = Value;

4

Portanto, se você já possui uma matriz, minha solução rápida será

var tempList = originalArray.ToList();
tempList.Add(newitem);

Agora basta substituir a matriz original pela nova

originalArray = tempList.ToArray();

Resolvido minha solução
praguan

3

Um novo Append<TSource>método foi adicionado ao IEnumerable<TSource>.NET Framework 4.7.1 e .NET Core 1.0.

Aqui está como usá-lo:

var numbers = new [] { "one", "two", "three" };
numbers = numbers.Append("four").ToArray();
Console.WriteLine(string.Join(", ", numbers)); // one, two, three, four

Observe que se você deseja adicionar o elemento no início da matriz, pode usar o novo Prepend<TSource>método.


2

Usar uma lista seria sua melhor opção para gerenciamento de memória.


2

Que tal usar um método de extensão? Por exemplo:

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> source, TSource item)
{
    return source.Union(new TSource[] { item });
}

por exemplo:

string[] sourceArray = new []
{
    "foo",
    "bar"
}
string additionalItem = "foobar";
string result = sourceArray.Union(additionalItem);

Observe que isso imita esse comportamento da extensão Uniion do Linq (usado para combinar duas matrizes em uma nova) e exigia que a biblioteca Linq funcionasse.


1

Eu concordo com o Ed. O C # não facilita isso da maneira que o VB faz com o ReDim Preserve. Sem uma coleção, você terá que copiar a matriz para uma maior.


2
Graças a Deus! ReDim é incrivelmente lento quando abusado. =)
Ed S.

ReDim Preservesimplesmente copia a matriz para uma lager. Não há redimensionamento milagroso da matriz.
Olivier Jacot-Descombes

1
string str = "string ";
List<string> li_str = new List<string>();
    for (int k = 0; k < 100; i++ )
         li_str.Add(str+k.ToString());
string[] arr_str = li_str.ToArray();

0
private static string[] GetMergedArray(string[] originalArray, string[] newArray)
    {
        int startIndexForNewArray = originalArray.Length;
        Array.Resize<string>(ref originalArray, originalArray.Length + newArray.Length);
        newArray.CopyTo(originalArray, startIndexForNewArray);
        return originalArray;
    }


0

Infelizmente, usar uma lista não funcionará em todas as situações. Uma lista e uma matriz são realmente diferentes e não são 100% intercambiáveis. Dependeria das circunstâncias, se isso fosse uma solução aceitável.


0

Como esta pergunta não está satisfeita com a resposta fornecida, gostaria de adicionar esta resposta :)

public class CustomArrayList<T> 
 {  
   private T[] arr;  private int count;  

public int Count  
  {   
    get   
      {    
        return this.count;   
      }  
   }  
 private const int INITIAL_CAPACITY = 4;  

 public CustomArrayList(int capacity = INITIAL_CAPACITY) 
 {  
    this.arr = new T[capacity];   this.count = 0; 
  } 

 public void Add(T item) 
  {  
    GrowIfArrIsFull();  
   this.arr[this.count] = item;  this.count++; 
  }  

public void Insert(int index, T item) 
{  
 if (index > this.count || index < 0)  
    {   
      throw new IndexOutOfRangeException(    "Invalid index: " + index);  
     }  
     GrowIfArrIsFull();  
     Array.Copy(this.arr, index,   this.arr, index + 1, this.count - index);          
    this.arr[index] = item;  this.count++; }  

    private void GrowIfArrIsFull() 
    {  
    if (this.count + 1 > this.arr.Length)  
    {   
      T[] extendedArr = new T[this.arr.Length * 2];  
      Array.Copy(this.arr, extendedArr, this.count);  
      this.arr = extendedArr;  
    } 
  }
 }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.