Estou trabalhando em um formulário do Windows para calcular UPC para números de item.
Criei com êxito um que lida com um número de item / UPC por vez, agora quero expandi-lo e fazer isso para vários números de item / UPCs.
Comecei e tentei usar uma lista, mas continuo preso. Eu criei uma classe auxiliar:
public class Codes
{
private string incrementedNumber;
private string checkDigit;
private string wholeNumber;
private string wholeCodeNumber;
private string itemNumber;
public Codes(string itemNumber, string incrementedNumber, string checkDigit, string wholeNumber, string wholeCodeNumber)
{
this.incrementedNumber = incrementedNumber;
this.checkDigit = checkDigit;
this.wholeNumber = wholeNumber;
this.wholeCodeNumber = wholeCodeNumber;
this.itemNumber = itemNumber;
}
public string ItemNumber
{
get { return itemNumber; }
set { itemNumber = value; }
}
public string IncrementedNumber
{
get { return incrementedNumber; }
set { incrementedNumber = value; }
}
public string CheckDigit
{
get { return checkDigit; }
set { checkDigit = value; }
}
public string WholeNumber
{
get { return wholeNumber; }
set { wholeNumber = value; }
}
public string WholeCodeNumber
{
get { return wholeCodeNumber; }
set { wholeCodeNumber = value; }
}
}
Em seguida, iniciei meu código, mas o problema é que o processo é incremental, ou seja, eu obtenho o número do item em uma visualização em grade por meio de caixas de seleção e os coloco na lista. Então eu pego o último UPC do banco de dados, retiro o dígito de verificação, depois incremento o número por um e o coloco na lista. Depois, calculo o dígito de verificação para o novo número e o coloco na lista. E aqui eu já recebo uma exceção de falta de memória. Aqui está o código que tenho até agora:
List<Codes> ItemNumberList = new List<Codes>();
private void buttonSearch2_Click(object sender, EventArgs e)
{
//Fill the datasets
this.immasterTableAdapter.FillByWildcard(this.alereDataSet.immaster, (textBox5.Text));
this.upccodeTableAdapter.FillByWildcard(this.hangtagDataSet.upccode, (textBox5.Text));
this.uPCTableAdapter.Fill(this.uPCDataSet.UPC);
string searchFor = textBox5.Text;
int results = 0;
DataRow[] returnedRows;
returnedRows = uPCDataSet.Tables["UPC"].Select("ItemNumber = '" + searchFor + "2'");
results = returnedRows.Length;
if (results > 0)
{
MessageBox.Show("This item number already exists!");
textBox5.Clear();
//clearGrids();
}
else
{
//textBox4.Text = dataGridView1.Rows[0].Cells[1].Value.ToString();
MessageBox.Show("Item number is unique.");
}
}
public void checkMarks()
{
for (int i = 0; i < dataGridView7.Rows.Count; i++)
{
if ((bool)dataGridView7.Rows[i].Cells[3].FormattedValue)
{
{
ItemNumberList.Add(new Codes(dataGridView7.Rows[i].Cells[0].Value.ToString(), "", "", "", ""));
}
}
}
}
public void multiValue1()
{
_value = uPCDataSet.UPC.Rows[uPCDataSet.UPC.Rows.Count - 1]["UPCNumber"].ToString();//get last UPC from database
_UPCNumber = _value.Substring(0, 11);//strip out the check-digit
_UPCNumberInc = Convert.ToInt64(_UPCNumber);//convert the value to a number
for (int i = 0; i < ItemNumberList.Count; i++)
{
_UPCNumberInc = _UPCNumberInc + 1;
_UPCNumberIncrement = Convert.ToString(_UPCNumberInc);//assign the incremented value to a new variable
ItemNumberList.Add(new Codes("", _UPCNumberIncrement, "", "", ""));//**here I get the OutOfMemoreyException**
}
for (int i = 0; i < ItemNumberList.Count; i++)
{
long chkDigitOdd;
long chkDigitEven;
long chkDigitSubtotal;
chkDigitOdd = Convert.ToInt64(_UPCNumberIncrement.Substring(0, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(2, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(4, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(6, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(8, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(10, 1));
chkDigitOdd = (3 * chkDigitOdd);
chkDigitEven = Convert.ToInt64(_UPCNumberIncrement.Substring(1, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(3, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(5, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(7, 1)) + Convert.ToInt64(_UPCNumberIncrement.Substring(9, 1));
chkDigitSubtotal = (300 - (chkDigitEven + chkDigitOdd));
_chkDigit = chkDigitSubtotal.ToString();
_chkDigit = _chkDigit.Substring(_chkDigit.Length - 1, 1);
ItemNumberList.Add(new Codes("", "",_chkDigit, "", ""));
}
É este o caminho certo para fazer isso, usando uma lista, ou devo procurar uma maneira diferente?
Code
classe) são redundantes e nada além de ruído, na verdade,{ get; private set; }
seria suficiente.Respostas:
Vou expandir meu comentário:
Uma análise rápida
As matrizes são boas quando você tem um número fixo de elementos que é improvável que seja alterado e deseja acessá-lo de maneira não sequencial.
As Listas Vinculadas são otimizadas para adições e remoções rápidas em cada extremidade, mas seu acesso é lento no meio.
As listas de matrizes (como
List<T>
em C #!) São uma mistura das duas, com adições bastante rápidas e acesso aleatório.List<T>
geralmente será sua coleção preferida quando você não tiver certeza do que usar.Como matrizes funcionam
A maioria das linguagens de modelo de matrizes é como dados contíguos na memória, dos quais cada elemento tem o mesmo tamanho. Digamos que tivemos uma matriz de
int
s (mostrada como [endereço: valor], usando endereços decimais porque sou preguiçoso)Cada um desses elementos é um número inteiro de 32 bits; portanto, sabemos quanto espaço ele ocupa na memória (32 bits!). E sabemos o endereço de memória do ponteiro para o primeiro elemento.
É trivialmente fácil obter o valor de qualquer outro elemento nessa matriz:
Digamos que nosso primeiro elemento seja '0'. Sabemos que nosso segundo elemento está em '32' (0 + (32 * 1)), e nosso terceiro elemento está em 64 (0 + (32 * 2)).
O fato de podermos armazenar todos esses valores próximos um do outro na memória significa que nossa matriz é o mais compacta possível. Isso também significa que todos os nossos elementos precisam permanecer juntos para que as coisas continuem funcionando!
Assim que adicionamos ou removemos um elemento, precisamos pegar todo o resto e copiá-los para algum novo local na memória, para garantir que não haja lacunas entre os elementos e que tudo tenha espaço suficiente. Isso pode ser muito lento , especialmente se você estiver fazendo isso toda vez que quiser adicionar um único elemento.
Listas Vinculadas
Diferentemente das matrizes, as Listas Vinculadas não precisam que todos os seus elementos estejam próximos um do outro na memória. Eles são compostos de nós, que armazenam as seguintes informações:
A lista em si mantém uma referência à cabeça e à cauda (primeiro e último nós) na maioria dos casos, e às vezes acompanha seu tamanho.
Se você quiser adicionar um elemento ao final da lista, tudo que você precisa fazer é obter a cauda , e alterar o seu
Next
para fazer referência a um novoNode
contendo o seu valor. Remover do final é igualmente simples - basta desreferenciar oNext
valor do nó anterior.Infelizmente, se você possui um
LinkedList<T>
com 1000 elementos e deseja o elemento 500, não há uma maneira fácil de pular direto para o 500º elemento, como ocorre com uma matriz. Você precisa começar na cabeça , e continue indo aoNext
nó, até que você tenha feito isso 500 vezes.É por isso que adicionar e remover de um
LinkedList<T>
é rápido (quando se trabalha nas extremidades), mas o acesso ao meio é lento.Edit : Brian ressalta nos comentários que as Listas Vinculadas correm o risco de causar uma falha na página, por não serem armazenadas na memória contígua. Isso pode ser difícil de comparar e pode tornar as Listas vinculadas ainda mais lentas do que você imagina, dadas as complexidades de tempo.
Melhor dos dois mundos
List<T>
compromete os doisT[]
eLinkedList<T>
cria uma solução razoavelmente rápida e fácil de usar na maioria das situações.Internamente,
List<T>
é uma matriz! Ele ainda tem que pular os bastidores da cópia de seus elementos ao redimensionar, mas faz alguns truques legais.Para iniciantes, adicionar um único elemento geralmente não faz com que a matriz copie.
List<T>
garante que sempre haja espaço suficiente para mais elementos. Quando acabar, em vez de alocar uma nova matriz interna com apenas um novo elemento, ele alocará uma nova matriz com vários novos elementos (geralmente o dobro do que atualmente possui!).As operações de cópia são caras,
List<T>
reduzindo-as o máximo possível, enquanto ainda permitem acesso aleatório rápido. Como efeito colateral, pode acabar desperdiçando um pouco mais de espaço do que uma matriz direta ou uma lista vinculada, mas geralmente vale a pena a troca.TL; DR
Use
List<T>
. Normalmente é o que você deseja e parece correto para você nessa situação (onde você está chamando .Add ()). Se você não tiver certeza do que precisa,List<T>
é um bom lugar para começar.Matrizes são boas para coisas de alto desempenho, "eu sei que preciso exatamente de X elementos". Como alternativa, eles são úteis para estruturas rápidas e únicas "Eu preciso agrupar essas X coisas que eu já defini juntas para poder fazer um loop sobre elas".
Existem várias outras classes de coleção.
Stack<T>
é como uma lista vinculada que opera apenas de cima.Queue<T>
funciona como uma lista primeiro a entrar, primeiro a sair.Dictionary<T, U>
é um mapeamento associativo não ordenado entre chaves e valores. Brinque com eles e conheça os pontos fortes e fracos de cada um. Eles podem criar ou quebrar seus algoritmos.fonte
int
indicação do número de elementos utilizáveis. Entre outras coisas, é possível copiar em massa vários elementos de uma matriz para outra, mas copiar entre listas geralmente requer elementos de processamento individualmente. Além disso, elementos de matriz podem ser passadosref
para coisas comoInterlocked.CompareExchange
, enquanto itens de lista não podem.List<>
funcionava sob o capô.(index+first)%length
.Embora a resposta do KChaloux seja ótima, eu gostaria de destacar outra consideração:
List<T>
é muito mais poderosa que uma matriz. Os métodos deList<T>
são muito úteis em muitas circunstâncias - uma matriz não possui esses métodos e você pode gastar muito tempo para implementar soluções alternativas.Portanto, de uma perspectiva de desenvolvimento, quase sempre uso
List<T>
porque, quando existem requisitos adicionais, eles costumam ser muito mais fáceis de implementar quando você usa umList<T>
.Isso leva a um problema final: meu código (não sei o seu) contém 90%
List<T>
, portanto, as matrizes não se encaixam muito bem. Quando as passo a passo, preciso chamar o.toList()
método delas e convertê-las em uma lista. é irritante e é tão lento que qualquer ganho de desempenho ao usar uma matriz é perdido.fonte
No entanto, ninguém mencionou esta parte: "E aqui eu já recebo uma exceção de falta de memória". O que é inteiramente devido a
É fácil ver o porquê. Não sei se você pretendia adicionar a uma lista diferente ou deveria apenas armazenar
ItemNumberList.Count
como uma variável antes do loop para obter o resultado desejado, mas isso é simplesmente quebrado.Programmers.SE é para "... interessado em perguntas conceituais sobre desenvolvimento de software ...", e as outras respostas o trataram como tal. Tente http://codereview.stackexchange.com , onde essa pergunta se encaixaria. Mas mesmo lá é horrível, pois podemos apenas assumir que esse código começa em
_Click
, que não tem chamada paramultiValue1
onde você diz que o erro acontece.fonte