Lea la fila de la tabla con múltiples opciones -- # campo con excel camp codereview Relacionados El problema

Read table row with multiple options


5
vote

problema

Español

Desarrollé un algoritmo para leer una fila de una tabla (específicamente, estoy leyendo desde un archivo de Excel).

Tengo tres condiciones sobre cuándo terminar la operación de lectura:

  • Cuando se encuentra una celda vacía (reconocida por un 9988776655544338
  • cuando se encuentra una célula con errores (que corresponde a un valor nulo)
  • Tanto las dos condiciones anteriores

Este es el algoritmo actual:

  public IEnumerable<string> ReadRow(string spreadsheet, int column, int row, ReadOptions readOptions = ReadOptions.ReadUntilEmpty) {     var values = new List<string>();      if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty) && readOptions.HasFlag(ReadOptions.ReadUntilCellError))     {         try         {             for (var currentColumn = column; ; currentColumn++)             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  // Cell has errors, so we exit from the loop                 if (value == null) break;                  values.Add(value);             }         }         catch (ElementNotFoundException)         {             // The row is terminated             // so we exit the loop withouth loggin any error         }     }     else if (readOptions.HasFlag(ReadOptions.ReadUntilCellError))     {         for (var currentColumn = column; ; currentColumn++)         {             try             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  // Cell has errors, so we exit from the loop                 if (value == null) break;                  values.Add(value);             }             catch (ElementNotFoundException)             {                 // The ReadOptions is not setted on ReadUntilEmpty                 // so we just ignore empty cells             }         }     }     else if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty))     {         try         {             for (var currentColumn = column; ; currentColumn++)             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  values.Add(value);             }         }         catch (ElementNotFoundException)         {             // The row is terminated             // so we exit the loop withouth loggin any error         }     }      return values; }   

y solo para referencia, la enumeración utilizada:

  each_with_index0  

¿Cómo puedo mejorarlo?

Además, ¿alguna idea de cómo puedo reutilizar este código para leer una columna en su lugar?

Original en ingles

I developing an algorithm to read a row from a table (specifically, I'm reading from an Excel file).

I have three conditions about when to terminate the Read operation:

  • When an empty cell is found (recognized by an ElementNotFoundException
  • When a cell with errors is found (which corresponds to a null value)
  • Both the two previous conditions

This is the current algorithm:

public IEnumerable<string> ReadRow(string spreadsheet, int column, int row, ReadOptions readOptions = ReadOptions.ReadUntilEmpty) {     var values = new List<string>();      if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty) && readOptions.HasFlag(ReadOptions.ReadUntilCellError))     {         try         {             for (var currentColumn = column; ; currentColumn++)             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  // Cell has errors, so we exit from the loop                 if (value == null) break;                  values.Add(value);             }         }         catch (ElementNotFoundException)         {             // The row is terminated             // so we exit the loop withouth loggin any error         }     }     else if (readOptions.HasFlag(ReadOptions.ReadUntilCellError))     {         for (var currentColumn = column; ; currentColumn++)         {             try             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  // Cell has errors, so we exit from the loop                 if (value == null) break;                  values.Add(value);             }             catch (ElementNotFoundException)             {                 // The ReadOptions is not setted on ReadUntilEmpty                 // so we just ignore empty cells             }         }     }     else if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty))     {         try         {             for (var currentColumn = column; ; currentColumn++)             {                 var value = ReadCell(spreadsheet, currentColumn, row);                  values.Add(value);             }         }         catch (ElementNotFoundException)         {             // The row is terminated             // so we exit the loop withouth loggin any error         }     }      return values; } 

And just for reference, the enumeration used:

[Flags] public enum ReadOptions {      ReadUntilEmpty,     ReadUntilCellError } 

How can I improve it?

Also, any idea on how I can reuse this code to read a column instead a row?

     
 
 

Lista de respuestas

5
 
vote
  • Siempre termina la lectura de la fila si el elemento no se encuentra. Esto significa que puede tener un solo bloque de prueba que envuelva su declaración IF.
  • En lugar de verificar (ns clojure-solution.core (:require [clojure.string :as string])) (defn parse-int [s] (Integer. s)) (defn parse-line [s] (map parse-int (string/split s #" "))) 9 en su primera declaración, use 99887776655443320 (o en lugar de y). Realmente no le importa si (defn get-loaf-dimensions [] (let [numLoaves (parse-int (read-line))] (map #(%1) (repeat numLoaves (comp parse-line read-line))))) (def squares (map #(* % %) (range 1 1001))) 1 se establece en ese punto; Sólo (defn get-loaf-dimensions [] (let [numLoaves (parse-int (read-line))] (map #(%1) (repeat numLoaves (comp parse-line read-line))))) (def squares (map #(* % %) (range 1 1001))) 2 asuntos. Esto elimina un bloque completo de la declaración de IF.
  • Puede ir un paso más allá y solo verificar la bandera justo antes, o con, la verificación de valor nulo.

      (defn get-loaf-dimensions []   (let [numLoaves (parse-int (read-line))]     (map #(%1) (repeat numLoaves (comp parse-line read-line)))))  (def squares (map #(* % %) (range 1 1001))) 3  

En última instancia, me di cuenta de que nunca hay una necesidad de verificar el indicador 998877776655443324 , por lo que probablemente podría simplemente dejar el enume y cambiar 99887776655443325 a un booleano con un valor predeterminado de (defn get-loaf-dimensions [] (let [numLoaves (parse-int (read-line))] (map #(%1) (repeat numLoaves (comp parse-line read-line))))) (def squares (map #(* % %) (range 1 1001))) 6 .

Resumen Esto para trabajar en columnas en lugar de filas es fácil. La lógica no cambia en absoluto. Simplemente lo llamas con el número de fila pasado al argumento de la columna y el número de columna pasó al argumento de la fila. Entonces, realmente, nombrando la parte difícil y me estoy esforzando en cualquier nombre en realidad, pero por el bien de dar un ejemplo ...

  (defn get-loaf-dimensions []   (let [numLoaves (parse-int (read-line))]     (map #(%1) (repeat numLoaves (comp parse-line read-line)))))  (def squares (map #(* % %) (range 1 1001))) 7  

Una nota final: No estoy completamente cómodo con el hecho de que el bloque de captura no contiene realmente ningún código. Se siente un poco hacky.

 
  • You always terminate the reading of the row if the element isn't found. This means you can have just one Try-Catch block that wraps your If statement.
  • Instead of checking for && in your first statement, use || (or instead of and). You don't really care if ReadUntilEmpty is set at that point; only ReadUntilCellError matters. This eliminates an entire block from the If statement.
  • You could go one step further and only check the flag just before, or with, the null value check.

    public IEnumerable<string> ReadRow(string spreadsheet, int column, int row, ReadOptions readOptions = ReadOptions.ReadUntilEmpty) {     var values = new List<string>();      try     {         for (var currentColumn = column; ; currentColumn++)         {             var value = ReadCell(spreadsheet, currentColumn, row);              if readOptions.HasFlag(ReadOptions.ReadUntilCellError))             {                 // Cell has errors, so we exit from the loop                 if (value == null) break;             }              values.Add(value);         }     }     catch (ElementNotFoundException)     {         // The row is terminated         // so we exit the loop withouth loggin any      }      return values; } 

Ultimately I realized there's never actually a need to check the ReadUntilEmpty flag, so you could probably just drop the Enum and change ReadUntilError to a Boolean with a default value of false.

Abstracting this to work on columns instead of rows is easy. The logic doesn't change at all. You just call it with the row number passed into the column argument and the column number passed into the row argument. So, really, naming the hard part and I'm drawing a blank on any actually useful names, but for the sake of giving an example...

public IEnumerable<string> ReadRow(string spreadsheet, int iteratorIndex, int secondaryIndex, ReadOptions readOptions = ReadOptions.ReadUntilEmpty) {     var values = new List<string>();      try     {         for (var index = iteratorIndex; ; index++)         {             var value = ReadCell(spreadsheet, index, secondaryIndex);              if readOptions.HasFlag(ReadOptions.ReadUntilCellError))             {                 // Cell has errors, so we exit from the loop                 if (value == null) break;             }              values.Add(value);         }     }     catch (ElementNotFoundException)     {         // The row is terminated         // so we exit the loop withouth loggin any      }      return values; } 

One final note: I'm not entirely comfortable with the fact that the catch block doesn't actually contain any code. It feels a bit hacky.

 
 
4
 
vote

AS @ CKUHN203 insinuada al final de su respuesta, el 9988776655544330 bloqueo.

El problema es que está capturando una excepción que debe ser evitable: leer una celda vacía no es algo que debe ser Excepcional en Excel después de todo.

Creo que si ReadCell1 devolvió un struct que representó el valor de una celda, no tendría que captar esa excepción.

algo como esto:

  public struct CellValueInfo {     private readonly bool _isEmpty;     public bool IsEmpty { get { return _isEmpty; } }      private readonly bool _isError;     public bool IsError { get { return _isError; } }      private readonly object _value;     public object Value { get { return _value; } }      public CellValueInfo(object value, bool isEmpty, bool isError)     {         _value = value;         _isEmpty = isEmpty;         _isError = isError;     } }   

concedido, esto podría mejorarse enormemente, pero es un punto de partida: una estructura inmutable que contiene la información que necesita: la idea es almacenar la información que le permite determinar si una celda tiene un valor válido, un error o esta vacio

No confíe en excepciones cuando puede evitarlas, especialmente con Excel Interop.

 

As @ckuhn203 hinted at the end of his answer, the empty catch block smells.

The problem is that you're catching an exception that should be avoidable: reading an empty cell isn't something that should be exceptional in Excel after all.

I think if ReadCell returned a struct that represented a cell's value, you wouldn't need to catch that exception.

Something like this:

public struct CellValueInfo {     private readonly bool _isEmpty;     public bool IsEmpty { get { return _isEmpty; } }      private readonly bool _isError;     public bool IsError { get { return _isError; } }      private readonly object _value;     public object Value { get { return _value; } }      public CellValueInfo(object value, bool isEmpty, bool isError)     {         _value = value;         _isEmpty = isEmpty;         _isError = isError;     } } 

Granted, this could be greatly improved, but it's a starting point: an immutable structure that contains the information you need - the idea is to store the information that lets you determine whether a cell has a valid value, an error, or is empty.

Don't rely on exceptions when you can avoid them, especially with Excel interop.

 
 
0
 
vote

Esta es la versión actual, desarrollada basada también en @ CKUHN203 Respuesta:

  [Flags] public enum ReadOptions {     ReadUntilEmpty = 1,     ReadUntilCellError = 2 }  var values = new List<string>();  for (var currentColumn = column; currentColumn < CellLocation.MaxColumnIndex; currentColumn++) {     string value;      if (!TryReadCell(spreadsheet, currentColumn, row, out value))     {         // An empty cell has been found         // so we exit the loop if requested by the options         if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty)) break;     }      // Cell has errors, so we exit from the loop if requested by the options     if (value == null && readOptions.HasFlag(ReadOptions.ReadUntilCellError)) break;      values.Add(value); } return values;   

Básicamente, tengo:

  • fijó la enumeración (faltaban los valores para las distintas banderas)
  • reemplazó el método ReadCell con un PryTreadCell, que devuelve un valor booleano, en su lugar, vomita una nueva excepción (mejorando también el rendimiento de esta manera)
  • movió las afirmaciones de IF dentro del bucle
 

This is the current version, developed based also on @ckuhn203 answer:

[Flags] public enum ReadOptions {     ReadUntilEmpty = 1,     ReadUntilCellError = 2 }  var values = new List<string>();  for (var currentColumn = column; currentColumn < CellLocation.MaxColumnIndex; currentColumn++) {     string value;      if (!TryReadCell(spreadsheet, currentColumn, row, out value))     {         // An empty cell has been found         // so we exit the loop if requested by the options         if (readOptions.HasFlag(ReadOptions.ReadUntilEmpty)) break;     }      // Cell has errors, so we exit from the loop if requested by the options     if (value == null && readOptions.HasFlag(ReadOptions.ReadUntilCellError)) break;      values.Add(value); } return values; 

Basically, I have:

  • Fixed the enumeration (the values for the various flags were missing)
  • Replaced the ReadCell method with a TryReadCell, that returns a boolean value instead throw up a new exception (improving also the performance in this way)
  • Moved the if statements inside the loop
 
 

Relacionados problema

7  Recuperando datos de archivos en la carpeta  ( Retrieving data from files in the folder ) 
Estoy a usar el código VBA para simplemente recuperar ciertos datos de todos los archivos de Excel en cierta carpeta y pegarlo en la hoja de cálculo de trabaj...

5  Excel a JSON Parser con http descargar  ( Excel to json parser with http download ) 
He estado trabajando en un proyecto ( enlace ) a Descargue una hoja de cálculo de Ransomware y propiedades conocidas y conviértase en JSON para que pueda cons...

3  Comparando células de dos hojas de trabajo  ( Comparing cells of two worksheets ) 
Con el siguiente código, trato de comparar el contenido de dos hojas de trabajo. La primera columna contiene una clave que es única y las siguientes columnas ...

2  Importando datos en Excel  ( Importing data into excel ) 
¿Existe una forma más fácil de importar datos en una matriz de Excel u otra estructura de datos? He intentado investigar colecciones, pero he encontrado la D...

2  Búsqueda de pruebas de abstracción y unidad en mesa Excel  ( Abstracting and unit testing lookups in excel table ) 
Fondo Tengo una solución de VBA que utilizo para ingerir informes de texto de inversión y reformatearlos para su análisis en Excel. Funciona, pero las macro...

5  Copiando datos de libros cerrados  ( Copying data from closed workbooks ) 
Soy un pasante en una empresa industrial en Brasil y sucede que estoy usando mucho en Excel. Acabo de empezar a jugar con VBA hace un par de días, ¡y me divie...

3  Coloque el cálculo del costo del campamento de verano utilizando las hojas de Google  ( Summer camp cost calculation using google sheets ) 
Estoy haciendo una hoja que suma el costo total para un campamento de verano después del registro. Cada padre puede registrarse hasta cinco niños. Ya he hecho...

6  Crear tabla que enumera la visibilidad de la hoja de trabajo  ( Create table that lists worksheet visibility ) 
Siguiendo mi pregunta anterior crear Una tabla que enumera las macros en un libro de trabajo o hoja de trabajo Aquí está mi Sub para determinar la visibilid...

6  Juego de serpientes - Dentro de la hoja de trabajo - Celdas como píxeles  ( Snake game within worksheet cells as pixels ) 
Desde mi intento bastante mediocre de hacer un juego de invasores del espacio, me topé con un caché de juegos de Visual Basic para solicitar juegos escritos p...

6  Fijación de archivos de reclamación médica a través del archivo de texto Lea / escribe  ( Fixing medical claim files through text file read write ) 
Con Gracias a @ Mat'Smug y @comintern por su aliento, aquí hay un programa que escribí para ayudar a mi equipo a reparar archivos de reclamación médica. El ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos