Estoy trabajando en un formulario de Windows para calcular el UPC para los números de artículo.
Creé con éxito uno que manejará un número de artículo / UPC a la vez, ahora quiero expandirlo y hacerlo para múltiples números de artículo / UPC.
Empecé e intenté usar una lista, pero sigo atascado. Creé una clase 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; }
}
}
Luego comencé con mi código, pero el problema es que el proceso es incremental, lo que significa que obtengo el número de artículo de una vista de cuadrícula a través de casillas de verificación y los pongo en la lista. Luego obtengo el último UPC de la base de datos, quito el dígito de control, luego incremento el número en uno y lo pongo en la lista. Luego calculo el dígito de control para el nuevo número y lo pongo en la lista. Y aquí ya tengo una excepción de memoria insuficiente. Aquí está el código que tengo hasta ahora:
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, "", ""));
}
¿Es esta la forma correcta de hacerlo, usando una lista, o debería mirar de otra manera?
Code
clase) son redundantes y nada más que ruido realmente{ get; private set; }
sería suficiente.Respuestas:
Ampliaré mi comentario:
Un desglose rápido
Las matrices son buenas cuando tiene un número fijo de elementos que es poco probable que cambie, y desea acceder a él de manera no secuencial.
Las listas enlazadas están optimizadas para adiciones y eliminaciones rápidas en cualquier extremo, pero son de acceso lento en el medio.
Las listas de matrices (como
List<T>
en C #!) Son una mezcla de las dos, con adiciones bastante rápidas y acceso aleatorio.List<T>
a menudo será su colección favorita cuando no esté seguro de qué usar.Cómo funcionan las matrices
La mayoría de los lenguajes modelan matrices como datos contiguos en la memoria, de los cuales cada elemento tiene el mismo tamaño. Digamos que teníamos una matriz de
int
s (mostrada como [dirección: valor], usando direcciones decimales porque soy vago)Cada uno de estos elementos es un número entero de 32 bits, por lo que sabemos cuánto espacio ocupa en la memoria (¡32 bits!). Y sabemos la dirección de memoria del puntero al primer elemento.
Es trivialmente fácil llegar al valor de cualquier otro elemento en esa matriz:
Digamos que nuestro primer elemento está en '0'. Sabemos que nuestro segundo elemento está en '32' (0 + (32 * 1)), y nuestro tercer elemento está en 64 (0 + (32 * 2)).
El hecho de que podamos almacenar todos estos valores uno al lado del otro en la memoria significa que nuestra matriz es lo más compacta posible. ¡También significa que todos nuestros elementos deben permanecer juntos para que las cosas sigan funcionando!
Tan pronto como agreguemos o eliminemos un elemento, debemos recoger todo lo demás y copiarlos en algún lugar nuevo en la memoria, para asegurarnos de que no haya espacios entre los elementos y que todo tenga suficiente espacio. Esto puede ser muy lento , especialmente si lo hace cada vez que desea agregar un solo elemento.
Listas vinculadas
A diferencia de las matrices, las listas enlazadas no necesitan que todos sus elementos estén uno al lado del otro en la memoria. Están compuestos por nodos, que almacenan la siguiente información:
La lista en sí misma mantiene una referencia a la cabeza y la cola (primer y último nodo) en la mayoría de los casos, y a veces realiza un seguimiento de su tamaño.
Si desea agregar un elemento al final de la lista, todo lo que necesita hacer es obtener la cola y cambiarla
Next
para hacer referencia a una nueva queNode
contenga su valor. Eliminar desde el final es igualmente simple: simplemente desreferenciar elNext
valor del nodo anterior.Desafortunadamente, si tiene un
LinkedList<T>
elemento con 1000 elementos y desea el elemento 500, no hay una manera fácil de saltar directamente al elemento número 500 como lo hay con una matriz. Debe comenzar en la cabeza y continuar hacia elNext
nodo, hasta que lo haya hecho 500 veces.Esta es la razón por la cual agregar y eliminar de a
LinkedList<T>
es rápido (cuando se trabaja en los extremos), pero acceder al medio es lento.Editar : Brian señala en los comentarios que las listas enlazadas tienen el riesgo de causar un error de página, debido a que no se almacenan en la memoria contigua. Esto puede ser difícil de evaluar, y puede hacer que las Listas Vinculadas sean incluso un poco más lentas de lo que cabría esperar dada su complejidad de tiempo.
Lo mejor de ambos mundos
List<T>
compromete a ambosT[]
yLinkedList<T>
presenta una solución razonablemente rápida y fácil de usar en la mayoría de las situaciones.Internamente,
List<T>
es una matriz! Todavía tiene que saltar a través de los aros de copiar sus elementos al cambiar el tamaño, pero hace algunos trucos geniales.Para empezar, agregar un solo elemento generalmente no hace que la matriz se copie.
List<T>
se asegura de que siempre haya suficiente espacio para más elementos. Cuando se agota, en lugar de asignar una nueva matriz interna con un solo elemento nuevo, asignará una nueva matriz con varios elementos nuevos (¡a menudo el doble de lo que tiene actualmente!).Las operaciones de copia son caras, por lo que debe
List<T>
reducirlas tanto como sea posible, al tiempo que permite un acceso aleatorio rápido. Como efecto secundario, puede terminar desperdiciando un poco más de espacio que una matriz directa o una lista vinculada, pero generalmente vale la pena el compromiso.TL; DR
Uso
List<T>
. Normalmente es lo que desea, y parece ser correcto para usted en esta situación (donde está llamando .Add ()). Si no está seguro de lo que necesita,List<T>
es un buen lugar para comenzar.Las matrices son buenas para cosas de alto rendimiento, "Sé que necesito exactamente elementos X". Alternativamente, son útiles para estructuras rápidas y únicas "Necesito agrupar estas X cosas que ya he definido juntas para poder recorrerlas".
Hay varias otras clases de colección.
Stack<T>
es como una lista vinculada que solo opera desde arriba.Queue<T>
funciona como una lista de primero en entrar, primero en salir.Dictionary<T, U>
es un mapeo asociativo desordenado entre claves y valores. Juega con ellos y conoce las fortalezas y debilidades de cada uno. Pueden hacer o deshacer sus algoritmos.fuente
int
indicar el número de elementos utilizables. Entre otras cosas, es posible copiar en masa múltiples elementos de una matriz a otra, pero la copia entre listas generalmente requiere el procesamiento de elementos individualmente. Además, los elementos de la matriz pueden pasarseref
a cosas comoInterlocked.CompareExchange
, mientras que los elementos de la lista no.List<>
funcionaba bajo el capó.(index+first)%length
.Si bien la respuesta de KChaloux es excelente, me gustaría señalar otra consideración:
List<T>
es mucho más poderosa que una matriz. Los métodos deList<T>
son muy útiles en muchas circunstancias: una matriz no tiene estos métodos y es posible que pase mucho tiempo para implementar soluciones alternativas.Entonces, desde una perspectiva de desarrollo, casi siempre uso
List<T>
porque cuando hay requisitos adicionales, a menudo son mucho más fáciles de implementar cuando está utilizando aList<T>
.Esto lleva a un problema final: mi código (no sé sobre el suyo) contiene 90%
List<T>
, por lo que las matrices no encajan realmente. Cuando las paso, tengo que llamar a su.toList()
método y convertirlos en una Lista: esto es molesto y es tan lento que se pierde cualquier ganancia de rendimiento al usar una matriz.fuente
Sin embargo, nadie mencionó esta parte: "Y aquí ya tengo una excepción de memoria insuficiente". Lo cual se debe enteramente a
Es claro ver por qué. No sé si pretendía agregar a una lista diferente, o simplemente debe almacenar
ItemNumberList.Count
como una variable antes del ciclo para obtener el resultado deseado, pero esto simplemente se rompe.Programmers.SE es para "... interesados en preguntas conceptuales sobre desarrollo de software ...", y las otras respuestas lo trataron como tal. Pruebe http://codereview.stackexchange.com en su lugar, donde encajaría esta pregunta. Pero incluso allí es horrible, ya que solo podemos suponer que este código comienza en
_Click
, que no tiene ninguna llamada amultiValue1
donde usted dice que ocurre el error.fuente