¿Tiene su propia biblioteca 'misc utils'? ¿De qué parte estás más orgulloso? [cerrado]

32

Sé que muchos de nosotros mantenemos nuestra pequeña biblioteca personal con herramientas y utilidades que usamos a menudo.

He tenido el mío desde que tenía 16 años, por lo que ha crecido hasta un tamaño bastante considerable. Algunas de las cosas que he escrito desde entonces se han agregado al marco. Escribí mi propia pequeña implementación de árboles de expresión para usar con algoritmos genéticos mucho antes de LINQ, lo que me gustó y me enorgulleció en ese momento, por supuesto, es bastante inútil ahora. Pero recientemente lo he estado revisando y actualizando a .NET 4.0 y volví a encender un interés.

Así que tengo curiosidad sobre para qué usas tu biblioteca. Tal vez podríamos obtener algunas ideas geniales para pequeños fragmentos útiles y compartirlas entre nosotros.

Entonces mis preguntas son:

  • ¿Tiene una biblioteca de servicios varios?
  • ¿De qué parte estás más orgulloso y por qué?

Da un ejemplo de código si quieres :-)

Nadie
fuente
Nadie parece estar votando respuestas ...
Joey Adams
@Joey Adams, ¿verdad? Actualmente 17 votos de preguntas y 6 votos de respuesta total .
Nicole
Realmente no veo respuestas que valgan la pena votar. ¿Qué significa para ellos un voto a favor? La naturaleza de la pregunta es tal que las respuestas solo obtienen un "oh. Agradable". tipo de reacción, y luego se vota todo o nada en absoluto. (Y no me gusta votar cada respuesta solo porque está ahí. Si nada más, estoy sin votos.: P)
Adam Lear
@ Anna Lear, ok, estás excusada :)
Nicole
3
Cualquier utilidad decente se debe poner en github y compartir con el mundo. No tiene sentido mantenerlo oculto si es realmente bueno.
Trabajo

Respuestas:

27

No.

He visto algunos efectos de pesadilla de una docena de desarrolladores, todos añadiendo sus propias pequeñas bibliotecas de estilo "util.h" a los proyectos, y lo han convertido en un desastre gigante de nombres y comportamientos inconsistentes. Al igual que PHP. Por eso evito hacerlo.

Evito tener que hacer eso usando entornos de programación que me brindan casi todas las herramientas y bibliotecas que necesito por adelantado siempre que sea posible, como C # y python.

whatsisname
fuente
77
Constantemente reescribo mi biblioteca con fines organizativos.
Maxpm
3
Los casos en que el paquete de utilidades se ha convertido en una pesadilla no significa que todos sean malos. No puedo ver cómo puede evitarlo y no tener más duplicación de código debido a eso. Y por lo tanto, peores pruebas y menos eficiencia.
Nicole
2
@Renesis: Los paquetes de utilidades son tan desastrosos como las declaraciones de goto. Claro, por sí solo no es tan malo, pero aparentemente siempre termina siendo un desastre tarde o temprano. En cuanto a la duplicación de código, si te encuentras haciendo una tarea similar en prácticamente todos tus proyectos, entonces, para algo como Python o C #, otras personas probablemente también lo hayan estado haciendo y probablemente esté en las bibliotecas estándar para entonces.
whatsisname
66
En mi experiencia, los ingenieros con su propia biblioteca favorecerán su uso antes que el proporcionado por el sistema, por lo que no es una buena práctica tener bibliotecas personales. Una vez tuve un tipo que estaba absolutamente convencido de que su función 'strlen' era más rápida que la proporcionada por el compilador, porque la escribió . Le tomó una simple demostración de cuán cansadas son un par de instrucciones de montaje en línea para que él reconozca que tal vez otras personas puedan hacerlo mejor.
JBRWilkinson
44
@JBRWilkinson Tu punto está bien entendido. No todos los programadores son aptos para desarrollar código común.
Nicole
15

SmartFormat

Mi utilidad favorita es una que escribí: un simple generador / formateador de cadenas que hace que sea muy fácil convertir datos en cadenas con la gramática correcta.

Por ejemplo, la mayoría de los programadores construir texto de una plantilla: "There are {0} items remaining" pero esto conduce a errores gramaticales: "There are 1 items remaining".

Así, SmartFormat le permite escribir: "There {0:is|are} {0} item{0:|s} remaining".

Simplemente reemplaza String.Format(...)con Smart.Format(...)y eso es todo!

El código SmartFormat es de código abierto: http://github.com/scottrippey/SmartFormat/wiki

Scott Rippey
fuente
Esto me recuerda el formato utilizado por java.text.MessageFormat.
barjak
@barjak ¡Interesante! Pasé mucho tiempo investigando el formato "condicional", ¡y nunca encontré nada similar hasta ahora! MessageFormattiene la ChoiceFormatclase que permite una sintaxis sorprendentemente similar! Un ejemplo de la documentación: "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.". Gracias por mencionar esta referencia.
Scott Rippey
@barjak Solo para validar mi punto, ¡ SmartFormat tiene muchas más funciones! El formato condicional funciona para cualquier tipo de datos, como bool, date, timespan y object; También es compatible con operadores avanzados, como "{Count:<0?negative|=5?five|>50&<100?large|other}". Tiene reflejo (es decir "There are {items.Length} items", puede formatear elementos de matriz y intervalos de tiempo. Además, tiene un modelo de complemento para admitir aún más funciones.)
Scott Rippey,
Parece ser poderoso, de hecho. El formato de las matrices es interesante.
barjak
@barjak: Sí, ¡el formato de matriz es realmente útil! Mira este ejemplo: Smart.Format("There are {0.Count} files: {0:'{}'|, |, and }.", files);daría como resultado "There are 3 files: 'a.txt', 'b.txt', and 'c.txt'.". No puedo imaginar la "localización" sin ella.
Scott Rippey
7

Combinador K (C #, Scala)

Utilizo el combinador K en Ruby con bastante frecuencia, principalmente en pliegues cuando la operación de plegado se realiza a través de un efecto secundario en lugar de un valor de retorno, como en este ejemplo:

some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1 }

Esto cuenta con qué frecuencia ocurre cada elemento some_collection. Desafortunadamente, en realidad no funciona, ya que el bloque debe devolver el nuevo valor del acumulador en cada iteración, pero en Ruby las asignaciones evalúan el valor asignado.

Por lo tanto, debe devolver de manera explícita el nuevo valor del acumulador de esta manera:

some_collection.reduce(Hash.new(0)) {|acc, el| acc[el] += 1; acc }

Pero considero que esa secuencia explícita es fea en este estilo funcional usando pliegues. El combinador K (llamado Object#tapen Ruby) al rescate:

some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}

Ya lo he perdido un par de veces en C # (principalmente porque, por alguna razón, los mutadores de colección como List.Addreturn en voidlugar de this) y Scala, así que llevo esto:

namespace GenericExtensions
{
    public static class GenericExtensions
    {
        public static T Tap<T>(this T o, Action<T> f)
        {
            Contract.Requires(o != null);
            Contract.Requires(f != null);

            f(o);
            return o;
        }

        public static T Tap<T>(this T o, Action f)
        {
            Contract.Requires(o != null);
            Contract.Requires(f != null);

            f();
            return o;
        }
    }
}

y en Scala:

class Tap[T](o: T) {
  def tap(f: T => Unit) = { f(o); o }
  def tap(f: => Unit) = { f; o }
}

object Implicits { implicit def any2Tap[T](o: T) = new Tap(o) }

Función de identidad (Ruby)

Algo que me falta en Ruby, es una forma muy bien nombrada de acceder a la función de identidad. Haskell proporciona la función de identidad bajo el nombre de id, Scala bajo el nombre de identity. Esto le permite a uno escribir código como:

someCollection.groupBy(identity)

El equivalente en Ruby es

some_collection.group_by {|x| x }

No sale exactamente de la lengua, ¿verdad?

La solución es

IDENTITY = -> x { x }

some_collection.group_by(&IDENTITY)

ForEach (.NET)

Otro método que falta en C #:

namespace IEnumerableExtensions
{
    public static class IEnumerableExtensions
    {
        public static void ForEach<T>(this IEnumerable<T> xs, Action<T> f)
        {
            Contract.Requires(xs != null);
            Contract.Requires(f != null);

           foreach (var x in xs) f(x);
        }
    }
}
Jörg W Mittag
fuente
3
Creo que su último ejemplo fue una decisión de diseño calculada. El concepto de un Actionimplica efectos secundarios que van en contra de los principios de diseño de LINQ.
ChaosPandion
1
@ChaosPandion: ¿Qué tiene esto que ver con LINQ?
Jörg W Mittag
@ Jörg W Mittag: las IEnumerableextensiones se agregaron para LINQ.
ChaosPandion
2
@ChaosPandion: Todavía no entiendo. ForEachNo es un operador LINQ. ¿Por qué deberían aplicarse restricciones que solo se aplican a los operadores de LINQ ForEach, que no es un operador de LINQ? ¿Y por qué los efectos secundarios están prohibidos IEnumerable.ForEachpero sí permitidos List.ForEach? Además, ¿por qué los efectos secundarios están prohibidos IEnumerable.ForEachpero sí permitidos foreach?
Jörg W Mittag
@ Jörg W Mittag: lo que estoy diciendo es que el hecho de que falten en las extensiones fue una decisión de diseño. El hecho de que List<T>tiene un ForEaches razonable teniendo en cuenta que es un tipo mutable.
ChaosPandion
6

Tengo un Java Type Converter. Tiene una firma pública

public static <T> T convert(Object sourceValue, Class<T> destinationType)

y hace todo lo posible para convertir el valor de origen al tipo de destino. Básicamente, te permite escribir de forma dinámica dentro de un lenguaje de escritura estática :-)

En realidad es útil con los tipos numéricos en caja. ¿Qué tan irritante es que no puedas poner un lugar Integerdonde Longse espera? No hay problema, solo conviértalo. ¿O qué pasa si su función espera un double, pero tiene nullque poner allí? Kaboom, un NPE. Pero pásalo converty obtendrás un NaN.

Joonas Pulakka
fuente
Solución interesante Siempre he pensado que Long debería extender Integer. Pero incluso entonces todavía tendría el problema del autoboxing (hasta donde sé, no hay forma de que el autoboxing funcione con la herencia). Además, +1 para NaNsoporte.
Nicole
NaNes excelente. Lástima que no haya tal cosa para los enteros. Lo he usado Integer.MIN_VALUEcomo una convención. Por lo general, es "lo suficientemente extraño" como para notarlo, a diferencia del valor predeterminado 0. No sé por qué el (auto) boxeo no se trata (Double) nullcomo NaN. Es la solución correcta obvia, en mi humilde opinión.
Joonas Pulakka
6

Del código misceláneo que he escrito, la mayoría de las cosas buenas están en CCAN ahora, mientras que el resto tiendo a encontrar mejores versiones de los proyectos de código abierto existentes. Me encuentro escribiendo cada vez menos código "misc" de propósito general, a favor de escribir variantes específicas de la aplicación de dicho código, o de escribir módulos de propósito general que puedo liberar por sí mismos.

do

Aquí hay una función y typedef que he usado más de una vez. Para las aplicaciones que necesitan sincronización, es difícil superar los milisegundos en términos de simplicidad:

#include <stdint.h>
#include <sys/time.h>

typedef int64_t msec_t;

static msec_t time_ms(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (msec_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

Y más funciones diversas de C que tiendo a usar una y otra vez (y más):

/* Remove a trailing newline, if present. */
void chomp(char *buffer)
{
    if (!*buffer)
        return;

    while (*buffer)
        buffer++;

    if (buffer[-1] == '\n')
        buffer[-1] = 0;
}

/*
 * Skip whitespace, update the pointer, and return it.
 * Example:
 *
 * switch (*skipSpace(&s)) {
 *     case '\0':
 *         ...
 *     case '(':
 *         ...
 */
const char *skipSpace(const char **sptr)
{
    const char *s = *sptr;
    while (isspace(*s))
        s++;
    *sptr = s;
    return s;
}

/* Scramble an array of items uniformly. */
void scramble(void *base, size_t nmemb, size_t size)
{
    char *i = base;
    char *o;
    size_t sd;
    for (;nmemb>1;nmemb--) {
        o = i + size*(rand()%nmemb);
        for (sd=size;sd--;) {
            char tmp = *o;
            *o++ = *i;
            *i++ = tmp;
        }
    }
}

Haskell

La nub :: (Eq a) => [a] -> [a]función de Haskell es O (n²) porque, por su firma de tipo, solo se permite probar si dos elementos son iguales. Una alternativa simple de O (n log n) es map head . group . sort, pero requiere forzar la lista de entrada completa antes de producir salida, mientras que nubpuede comenzar a producir salida de inmediato. La siguiente es una alternativa O (n log n) nubque recopila elementos ya vistos en un Data.Set:

module Nub (nub') where

import Prelude
import Data.Set (empty, member, insert)

nub' :: Ord a => [a] -> [a]
nub' xs = loop xs empty where
    loop [] _ = []
    loop (x:xs) set =
        if x `member` set
            then loop xs set
            else x : loop xs (insert x set)

En Haskell, utilizo alternativas a sequence, mapM, forM, replicateM, y filterM. Estas acciones generan una lista, pero la lista no se puede usar hasta que la acción se complete por completo (si está usando una mónada estricta como IO). Las alternativas construyen la lista al revés en lugar de formar una torre de troncos, lo que encontré a través del benchmarking como más rápido, al menos con GHC.

sequence' :: Monad m => [m a] -> m [a]
sequence' ms = loop ms [] >>= return . reverse where
    loop []     xs = return xs
    loop (m:ms) xs = do
        x <- m
        loop ms (x:xs)

mapM' :: Monad m => (a -> m b) -> [a] -> m [b]
mapM' f xs = sequence' $ map f xs

forM' :: Monad m => [a] -> (a -> m b) -> m [b]
forM' = flip mapM'

replicateM' :: Monad m => Int -> m a -> m [a]
replicateM' n x = sequence' (replicate n x)

filterM' :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM' pred xs = loop xs [] >>= return . reverse where
    loop []     xs' = return xs'
    loop (x:xs) xs' = do
        keep <- pred x
        loop xs (if keep then (x:xs') else xs')

Nota: sequence_, mapM_, forM_, y replicateM_las funciones siguen siendo una mejor opción si usted no está interesado en la lista de resultados.

Joey Adams
fuente
+1 para CCAN, aunque podría considerarse un poco parcial :)
Tim Post
4

Terminé implementando split / join ala Perl en idiomas que no lo tienen.

También he reimplementado atoi e itoa en C más veces de las que quiero pensar (basura de sistemas integrados).

Paul Nathan
fuente
4

No.

Hago la mayor parte de mi codificación en Java, y la mejor práctica es reutilizar "utils" de las bibliotecas de Apache Commons y proyectos similares.

Si usted es objetivo al respecto, hay pocos casos en los que su propia colección de "utilidades" será una mejora significativa en lo que otras personas ya han hecho. Y si no es una mejora, entonces su biblioteca de utilidades es probablemente una pérdida de tiempo de desarrollo y una molestia / carga para los futuros mantenedores.

Stephen C
fuente
3

Tuve algunas manipulaciones de fechas que realicé usando Java, luego comencé a usar JodaTime ya que había escuchado cosas buenas al respecto y se incluirá en Java 7 (no estoy seguro de si este es el caso, pero incluso si no lo es todavía vale la pena usarlo en mi humilde opinión).

Convirtió una clase de más de 50 líneas en una línea con aproximadamente tres llamadas a métodos encadenados.

Para los curiosos, implicaba obtener la fecha de cada día de n semanas pasadas: por ejemplo, la cifra de ventas de un lunes hace 10 semanas, etc., etc.

Y aquí hay parte de eso

public static DateTime getDayPreviousWeek(DateTime dt, DayOfWeek dayOfWeek, int n_weeks) {
       return dt.minusWeeks(n_weeks).dayOfWeek().setCopy(dayOfWeek.getDayAsString());
}
NimChimpsky
fuente
Java tiene métodos de extensión?
Kugel
no, pero creo que podría estar recibiendo en la versión 7
NimChimpsky
2

Siempre tengo un utilspaquete de algún tipo, incluso en Java, pero mi colección de utilidades de PHP es la más reutilizada. Hay tantas buenas bibliotecas en Java que ya tengo una biblioteca incluida en el proyecto o necesito diseñar algunas utilidades que faltan por mi cuenta. Las bibliotecas PHP tienden a hacer demasiado para querer incluirlas en mis proyectos.

Me gusta esta función para PHP, refinada con ayuda de StackOverflow ...

function getValueFromDotKey(&$context, $name) {
    $pieces = explode('.', $name);
    foreach ($pieces as $piece) {
        if (!is_array($context) || !array_key_exists($piece, $context)) {
            // error occurred
            return null;
        }
        $context = &$context[$piece];
    }
    return $context;
}

Es similar a BeanUtils de Apache para Java, y lo uso para un propósito similar, dando a los elementos de formulario en un lenguaje de plantilla una sola clave que puede obtener / establecer un valor anidado en una matriz fuente:

$source = array('a' => array('b' => 5));

$val = getValueFromDotKey($source, 'a.b');

Por supuesto, ser PHP, quería mantener el método de lo más ligero posible por lo que no es muy tantas funcionalidades como BeanUtils;)

Nicole
fuente
2

La biblioteca estándar de Scala carece de algunas de las funciones de orden superior más utilizadas.

Dos funciones que necesito con mayor frecuencia:

// #1: unfold
def unfold[T, R](init: T)(f: T => Option[(R, T)]): List[R] = f(init) match {
  case None => Nil
  case Some(r, v) => r :: unfold(v)(f)
}

// #2: zipWith
def zipWith[A, B, C](xs: List[A], ys: List[B])(f: (A, B) => C): List[C] = {
  (xs, ys).zipped.map(f)
}
missingfaktor
fuente
1

Actualmente no. Tenía uno cuando estaba haciendo C, pero ahora que hago Java, ya no tiene sentido, teniendo en cuenta todas las bibliotecas estándar disponibles, además de todas las ventajas que provienen del proyecto Apache.

Una de las cosas útiles en mi C lib fue una implementación de máquina de estado finito rápida y sucia, que permitió la definición de una máquina de estado finito con solo dos cadenas y una serie de cadenas. Podría usarse para verificar cadenas con reglas (p. Ej., "Debe tener 4..6 caracteres de largo, primero una letra, resto de dígitos"), pero la disponibilidad de expresiones regulares hizo que esa cosa fuera completamente inútil.

usuario281377
fuente
1

No puedo escribir IU de escritorio ahora sin diálogos dinámicos , basados ​​en la ejecución diferencial . Es un truco con el que me topé alrededor de 1985, y lo he vuelto a implementar en varios idiomas más de lo que puedo recordar.

Mike Dunlavey
fuente
1

Descubrí que estaba escribiendo una gran cantidad del mismo código en django, haga esto común, luego común, y finalmente lo común. Básicamente, obtenga uno o más elementos de la base de datos, o guarde los resultados de un formulario.

Si cada una de estas cosas ocurre solo una vez en una vista, entonces puedo usar las vistas genéricas de django. Desafortunadamente, esos no son realmente compostables, y necesitaba hacer varias cosas en secuencia.

Así que fui y escribí una biblioteca de vistas aún más genérica, una que funcionó al crear primero una lista de acciones a partir de conjuntos de consultas relevantes (o lo que sea), y luego envolvió la lista en una vista.

Todavía tengo que escribir algunas vistas a mano, pero estas suelen ser lo suficientemente complejas como para que no haya muchas cosas reutilizables en ellas. Toda la repetitiva aterriza en otro lugar, ya sea una vista genérica o como un decorador de vistas (a menudo una vista genérica decorada). Esto generalmente termina siendo aproximadamente el 10% de los controladores que escribo, ya que algunos controladores genéricos pueden hacer todo lo demás.

SingleNegationElimination
fuente
1

Sí, pero solo para estructuras idiomáticas específicas de dominio (como contenedores específicos de objetos de juego).

Como son herramientas de utilidad simples que cualquier cosa compleja, no estoy orgulloso de nada allí. Soy el usuario único en este momento de todos modos, así que no hay nada de qué enorgullecerse.

Klaim
fuente
1

Ordenación indirecta de C ++, basada en el STL sorty una plantilla functor.

La necesidad de una ordenación indirecta (en la que el resultado deseado eran los índices de permutación que resultarían de la ordenación de los datos, pero no los datos ordenados en sí) apareció muchas veces en varios proyectos. Siempre me pregunté por qué STL no proporcionó una implementación para ello.

Otro era un vector cíclico C ++, donde los índices positivos y negativos son módulos con el tamaño del vector (de modo que cualquier valor entero es un índice válido para el vector).

rwong
fuente
-4

Escribí un pequeño paquete de utilidades cuando estaba desarrollando Java en mi Comp. Clase de ciencia en el instituto. Estoy muy orgulloso de mi generador de números aleatorios.

/**
* Returns a random integer.
*
* @returns    int    Random integer
*/
public static int getRandom()
{
    return 4; // Chosen by a fair dice roll.
              // Guaranteed to be random.
}

Atrezzo a mi inspiración.

Josh K
fuente
12
vamos, xkcd ....
Darknight
2
Vamos, no importa.
Josh K
1
Con sus votos actuales en -2, supongo que realmente importa ...
user7676
8
El plagio es la forma más alta de adulación, excepto cuando es obvio.
Maxpm
55
Bueno, el botón de voto negativo dice: "Esta respuesta no es útil". Creo que hay una necesidad de un botón adicional: "... pero seguro que es divertido"
skajfes