Enumeración ordenada: IEnumerable o Array (en C #)?

8

Contexto típico: hago un método de extensión para una colección que considera que los elementos están ordenados. La función comienza al principio, en el índice 0, y el orden tiene importancia. Ejemplos: Agrupación por secuencia o índices de un elemento .

Sin embargo, siempre estoy perplejo en cuanto a qué extender: IEnumerable<T>o T[]. Mi razonamiento fue la claridad del propósito: una matriz tiene una noción de orden, mientras que un IEnumerable es implementado por muchas colecciones genéricas, no todas las cuales tienen una noción de orden:

  • Diccionario - sin ordenar
  • HashSet - sin ordenar
  • LinkedList - ordenado
  • Lista - ordenada
  • Cola - ordenada
  • SortedDictionary - ordenado (no orden original)
  • SortedList - ordenado (no orden original)
  • SortedSet - ordenado (orden no original)
  • Pila - invertida

Así como cualquier otra implementación que pueda o no ordenarse.

Además, no estoy seguro de si el enumerador se restablece si no se completa una enumeración, así que si eso es una preocupación, ¿quién sabe en qué punto comenzaría la enumeración? Enumerar una matriz siempre comenzaría desde el principio.

Entonces, para mí, tiene más sentido extender a T[]. ¿Pero estoy en lo cierto al pensar eso? ¿Me estoy preocupando demasiado? ¿Cuál es el enfoque adecuado para garantizar la enumeración "ordenada"?

MPelletier
fuente

Respuestas:

13

No estoy seguro de si el enumerador se restablece si no se completa una enumeración, así que si eso es una preocupación, ¿quién sabe en qué punto comenzaría la enumeración? Enumerar una matriz siempre comenzaría desde el principio.

Estas dos oraciones me hacen pensar que tienes malentendidos profundos sobre cómo funciona el patrón enumerable. ¿Puede explicar por qué cree que un enumerador abandonado tiene algo que ver con una enumeración posterior ?

Un enumerable es un dispositivo que produce enumeradores . Si se abandona un enumerador, eso no afecta en modo alguno al enumerable. Si vendo libros, y Bob compra un libro y solo lo lee hasta la mitad, eso no significa que cuando vendo una copia diferente del libro a Alice, ella tenga que comenzar a leer donde lo dejó Bob.

Siempre estoy perplejo en cuanto a qué extender: IEnumerable<T>o T[]. Mi razonamiento fue la claridad del propósito: una matriz tiene una noción de orden, mientras que un IEnumerable es implementado por muchas colecciones genéricas, no todas las cuales tienen una noción de orden:

¿Su método de extensión necesita (1) acceder a la colección fuera de servicio? (2) escribir a la colección?

Si es así, extienda. IList<T>Si no, extienda IEnumerable<T>.

¿Qué pasa con: (3) pasar la colección a un método que espera una matriz?

Luego extienda la matriz.

Su pregunta es básicamente "No sé si extender Animal o Jirafa". Si su método de extensión no es específico para Jirafas, extienda Animal. Si su método de extensión no es específico de las matrices, extienda todas las listas. Si no es específico para las listas, extienda todas las secuencias. Si no es específico para las secuencias, es probable que un método de extensión sea el mecanismo incorrecto para usted; Recomiendo no extender todos los objetos.

Eric Lippert
fuente
Tengo una gran y vergonzosa falta de conocimiento de cómo funciona el patrón enumerable. Supongo que por eso estoy aquí preguntando esto.
MPelletier
Maldición, había olvidado por completo mi clase de estructura de datos. ¡Por supuesto que no afecta a las enumeraciones posteriores! Me he cubierto de vergüenza ... :(
MPelletier
@MPelletier: su pregunta aún tiene valor. ¿Es seguro / tiene sentido ejecutar un algoritmo donde el orden es importante, por ejemplo, en a Dictionary? Probablemente no. Como dijo Scott Meyers: "La mejor manera de evitar el uso incorrecto es hacer que dicho uso sea imposible". . ¿Es posible / sería beneficioso hacerlo en este escenario?
Steven Jeuris
1
@EricLippert: Los 3 puntos que mencionas son razones por las que tiene que extender matriz. La verdadera pregunta es, como en mi comentario anterior, ¿valdría la pena evitar el uso incorrecto? Esperando que pueda ampliar un poco sobre eso ...
Steven Jeuris
@StevenJeuris Su pregunta no sería necesaria si C # se diseñara correctamente y tuviera una interfaz ISortedCollection <T>, que ampliaría si necesita que se ordene la colección. Pero como no es así, la única forma de evitar el mal uso en el momento de la compilación es extender un tipo demasiado estrecho (IList <T>) o extender IEnumerable <T> y hacer un tipo innecesario.
Jim Balter
2

Creo que desea combinar 2 conceptos diferentes en 1. La estructura de datos y su orden de contenido son 2 cosas separadas.

Ordenar es un tema complicado. Por ejemplo, ¿qué significa ordenar una lista de personas? Incluso cuando se define la clave de orden / clasificación, debe tener una dirección y debe decidir qué hacer con los valores nulos (si los hay), problemas de fecha, etc.

Si el pedido de datos es importante para su método, entonces puede ser su método el responsable de ordenar los datos como parte de su configuración en lugar de solicitar que la persona que llama solicite los datos. Algunos algoritmos de coincidencia de cadenas utilizan un enfoque similar en el que se construye un diccionario dentro del método de búsqueda a partir de la cadena aprobada antes de buscar la cadena. Sé que este no es el caso exacto, pero es el ejemplo más cercano que se me ocurre.

Ninguna posibilidad
fuente
2
Un método de pedido como argumento ... Hmmm, ¡interesante!
MPelletier
Incluso entonces, el orden podría ser implícito. Ese es el problema principal que estoy teniendo. Entiendo que el concepto de LINQ es emular las funciones de la base de datos y, según 1NF, los registros no están ordenados. Desafortunadamente, el mundo real rara vez es 1NF.
MPelletier
"el mundo real rara vez es 1NF", es cierto en algunos casos, pero no estoy seguro de cómo afectaría eso al caso que usted describe aquí.
NoPuerto
1NF : "No hay un orden de arriba a abajo para las filas". Eso es lo que está pasando aquí, creo. Hay pedidos de arriba a abajo en los registros, en muchas "colecciones" sueltas. LINQ está diseñado para trabajar en colecciones como si fueran bases de datos, pero puede haber un orden de arriba a abajo, de ahí la contradicción que acabo de ver.
MPelletier
1

IEnumerable declara que la colección que tiene se puede enumerar; No implica nada sobre el contenido. Esto no es algo malo: los contenedores pueden tener capacidades y restricciones adicionales además de las interfaces individuales.

(No veo cómo una matriz es mejor aquí: es indexable, al igual que una IList y otros contenedores, pero no hay nada en la indexación que implique el orden de los datos. Su lista es un poco extraña: algunos elementos están "ordenados "en el sentido de que conservan el orden de inserción, otros están" ordenados "tal como están ordenados. Son dos cosas diferentes. Aparte de SortedSet / SortedList / SortedDictionary, no debe suponer que los datos están en un orden particular a menos que maneje eso dentro de su propio código.)

Sin embargo, IEnumerable proporciona una extensión LINQ que le permite .OrderBy, por lo que cualquier cosa que sea enumerable se puede devolver en un orden ordenado IOrderedEnumerable. Sin embargo, esa es una interfaz específica de LINQ (y no está implementada de manera predeterminada por SortedSet / SortedList / SortedDictionary, por lo que podría no tener sentido extender esa interfaz en particular ...)

Joe
fuente
2
Lo que quiero evitar es hacer una serie de funciones que funcionen "solo si se ordenan", luego, meses después, alguien usa la biblioteca en una colección desordenada y se pregunta por qué está dando resultados extraños. Además de una buena documentación que todos habrán leído detenidamente, por supuesto.
MPelletier
Y no creo que extender IOrderedEnumerable me haga fanático. Algunas listas ya están ordenados (creo un archivo de registro analizada, por ejemplo, el orden es el número de línea, pero no hay razón para hacerlo. Ordenar por ella si se lee de forma secuencial.
MPelletier
No hay un decorador / interfaz hoy que pueda decirle / advertir a los usuarios que se necesita una colección ordenada para su método de extensión. Especialmente para datos arbitrarios, ¿cómo podría saber (sin una función de comparación) si los datos fueron ordenados o no?
Joe