Hai la tua libreria 'misc utils'? Di quale parte sei più orgoglioso? [chiuso]

31

So che molti di noi gestiscono la nostra piccola biblioteca personale con strumenti e utilità che usiamo spesso.

Ho avuto il mio da quando avevo 16 anni, quindi è cresciuto fino a dimensioni abbastanza considerevoli. Alcune delle cose che ho scritto sono state aggiunte al framework. Ho scritto la mia piccola implementazione di alberi di espressione da utilizzare con algoritmi genetici molto prima di LINQ, cosa che mi piace e di cui ero orgoglioso al momento - ovviamente è piuttosto inutile ora. Ma di recente l'ho esaminato e aggiornato a .NET 4.0 e ho riacceso un interesse.

Quindi sono curioso di sapere per cosa usi la tua libreria. Forse potremmo ottenere alcune idee interessanti per utili piccoli frammenti e condividerli tra di noi.

Quindi le mie domande sono:

  • Disponi di una libreria di utilità varie
  • Di quale parte sei più orgoglioso e perché?

Fornisci un esempio di codice se ti piace :-)

    
posta Nobody 07.12.2010 - 16:30
fonte

16 risposte

26

No.

Ho visto alcuni effetti da incubo di una dozzina di sviluppatori che aggiungono le loro piccole librerie di stile "util.h" ai progetti, trasformandoli in un gigantesco casino di nomi e comportamenti di funzioni incoerenti. Proprio come PHP. Quindi per questo motivo evito di farlo.

Evito di doverlo fare usando ambienti di programmazione che mi forniscono quasi tutti gli strumenti e le librerie che mi servono in anticipo quando possibile, come C # e python.

    
risposta data 07.12.2010 - 20:29
fonte
16

SmartFormat

La mia utility preferita è quella che ho scritto - un semplice generatore di stringhe / formattatore che rende davvero facile trasformare i dati in stringhe con la grammatica corretta.

Ad esempio, la maggior parte dei programmatori crea testo da un modello: %codice% ma questo porta a errori grammaticali: "There are {0} items remaining" .

Quindi SmartFormat ti consente di scrivere: "There are 1 items remaining" .

Sostituisci solo "There {0:is|are} {0} item{0:|s} remaining" con String.Format(...) e il gioco è fatto!

Il codice SmartFormat è open source: link

    
risposta data 08.12.2010 - 00:21
fonte
7

K Combinator (C #, Scala)

Uso il combinatore K in Ruby abbastanza spesso, principalmente nelle pieghe quando l'operazione di piegatura viene eseguita attraverso un effetto collaterale piuttosto che un valore di ritorno, come in questo esempio:

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

Conta quante volte ogni elemento si verifica in some_collection . Sfortunatamente, in realtà non funziona, poiché il blocco deve restituire il nuovo valore dell'accumulatore ad ogni iterazione, ma nelle assegnazioni di Ruby valutare il valore assegnato.

Quindi, devi restituire ecicamente il nuovo valore dell'accumulatore in questo modo:

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

Ma trovo il sequenziamento così esplicito brutto in questo stile funzionale-ish che usa le pieghe. Il combinatore K (chiamato Object#tap in Ruby) al salvataggio:

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

L'ho già perso un paio di volte in C # (principalmente perché per qualche motivo i mutatori di raccolta come List.Add return void invece di this ) e Scala, quindi mi porto dietro questo:

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;
        }
    }
}

e in 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) }

Funzione Identity (Ruby)

Qualcosa che mi manca in Ruby, è un modo ben definito per accedere alla funzione di identità. Haskell fornisce la funzione di identità con il nome di id , Scala con il nome di identity . Questo permette di scrivere codice come:

someCollection.groupBy(identity)

L'equivalente in Ruby è

some_collection.group_by {|x| x }

Non si stacca esattamente la lingua, vero?

La correzione è

IDENTITY = -> x { x }

some_collection.group_by(&IDENTITY)

ForEach (.NET)

Un altro metodo decisamente mancante in 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);
        }
    }
}
    
risposta data 07.12.2010 - 19:10
fonte
6

Ho un convertitore di tipo Java. Ha una firma pubblica

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

e fa del suo meglio per convertire il valore sorgente nel tipo di destinazione. Ti consente essenzialmente di digitare dinamicamente in una lingua tipizzata in modo statico: -)

In realtà è utile con tipi numerici in scatola. Quanto è irritante che non si possa mettere un Integer a cui è previsto Long ? Nessun problema, convertilo. O se la tua funzione si aspetta un double , ma hai un null da mettere lì? Kaboom, un NPE. Ma passa a convert e ottieni NaN .

    
risposta data 08.12.2010 - 08:02
fonte
6

Del codice misc ho scritto, la maggior parte delle cose buone è in CCAN ora, mentre il resto tendo a trovare migliori versioni di progetti open source esistenti. In questi giorni mi trovo a scrivere un codice "misc" meno generico, a favore della scrittura di varianti specifiche dell'applicazione di tale codice o della scrittura di moduli generali che posso rilasciare da soli.

C

Ecco una funzione e typedef che ho usato più di una volta. Per le applicazioni che richiedono tempismo, è difficile battere i millisecondi in termini di semplicità:

#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;
}

E più varie funzioni C che tendo ad usare più e più volte (e oltre):

/* 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 '
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)
': * ... * 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 funzione nub :: (Eq a) => [a] -> [a] di Haskell è O (n²) perché, con la sua firma del tipo, è consentito testare solo se due elementi sono uguali. Una semplice alternativa di O (n log n) è map head . group . sort , ma richiede di forzare l'intera lista di input prima di produrre output, mentre nub può iniziare a produrre immediatamente l'output. Quanto segue è un'alternativa O (n log n) a nub che raccoglie gli elementi già visti in Data.Set :

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')

In Haskell, uso alternative a sequence , mapM , forM , replicateM e filterM . Queste azioni generano ciascuna un elenco, ma l'elenco non può essere utilizzato fino a quando l'azione non viene completata nella sua interezza (se si sta utilizzando un monade rigido come IO). Le alternative costruiscono la lista al contrario piuttosto che formare una torre di thunk, che ho trovato attraverso il benchmarking per essere più veloce, almeno con GHC.

#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;
}

Nota: le funzioni sequence_ , mapM_ , forM_ e replicateM_ sono ancora una scelta migliore se non sei interessato alla lista dei risultati.

    
risposta data 07.12.2010 - 20:51
fonte
4

Finisco per implementare split / join ala Perl in lingue che non ce l'hanno.

Ho anche reimplementato atoi e itoa in C più volte di quanto voglio pensare (sistemi embedded junk).

    
risposta data 08.12.2010 - 02:14
fonte
4

No.

Realizzo la maggior parte della mia codifica in Java e le migliori pratiche sono il riutilizzo di "utilità" dalle biblioteche di Apache Commons e progetti simili.

Se sei obiettivo a riguardo, ci sono pochi casi in cui la tua collezione di "utilità" sarà un miglioramento significativo su ciò che altre persone hanno già fatto. E se non si tratta di un miglioramento, la libreria dei tuoi programmi di utilità è probabilmente uno spreco di tempo di sviluppo e una seccatura / difficoltà per i futuri manutentori.

    
risposta data 08.12.2010 - 07:01
fonte
3

Ho avuto alcune manipolazioni di date che ho eseguito utilizzando Java, quindi ho iniziato a utilizzare JodaTime come avevo sentito parlare bene su di esso e il suo essere incluso in Java 7 (non è sicuro se questo è ancora il caso, ma anche se non è ancora valsa la pena di usarlo imho).

Ha trasformato una classe di oltre 50 linee in una riga con circa tre chiamate di metodo concatenate.

Per i curiosi è stato necessario ottenere la data per ogni giorno di n settimane passate: ad esempio il dato sulle vendite per un lunedì 10 settimane fa ecc. ecc.)

E qui è parte di esso

public static DateTime getDayPreviousWeek(DateTime dt, DayOfWeek dayOfWeek, int n_weeks) {
       return dt.minusWeeks(n_weeks).dayOfWeek().setCopy(dayOfWeek.getDayAsString());
}
    
risposta data 07.12.2010 - 17:13
fonte
2

Ho sempre un pacchetto utils di qualche tipo, anche in Java, ma la mia raccolta di utilità PHP è la più riutilizzata. Ci sono così tante buone librerie in Java, che ho già una libreria inclusa nel progetto o ho bisogno di progettare solo alcuni programmi di utilità mancanti da solo. Le librerie PHP tendono a fare troppo per me per volerle includere nei miei progetti.

Ho un po 'come questa funzione per PHP, perfezionato con help su 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;
}

È simile a BeanUtils di Apache per Java, e io lo uso per uno scopo simile, dando agli elementi del modulo in un linguaggio template una singola chiave che può ottenere / impostare un valore annidato in una matrice sorgente:

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

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

Ovviamente, essendo PHP, volevo mantenere il metodo il più leggero possibile in modo che non fosse abbastanza come featureful come BeanUtils ;)

    
risposta data 07.12.2010 - 19:22
fonte
2

La libreria standard di Scala non ha alcune funzioni di ordine superiore più comunemente utilizzate.

Due di queste funzioni che mi servono più spesso:

// #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)
}
    
risposta data 08.12.2010 - 06:33
fonte
1

Attualmente, no. Ne avevo uno quando stavo facendo C, ma ora che faccio Java, non ha più senso, considerando tutte le librerie standard disponibili, oltre a tutte le chicche provenienti dal progetto Apache.

Una delle cose utili nella mia C lib era un'implementazione della macchina a stati finiti rapida e complessa, che consentiva la definizione di una macchina a stati finiti con solo due stringhe e una serie di stringhe. Potrebbe essere usato per controllare le stringhe rispetto alle regole (ad es. "Deve essere di 4,6 caratteri, prima una lettera, cifre di riposo"), ma la disponibilità di espressioni regolari ha reso quella cosa completamente inutile.

    
risposta data 07.12.2010 - 22:59
fonte
1

Non riesco a scrivere interfacce utente desktop ora senza finestre di dialogo dinamiche , in base a esecuzione differenziale . È un trucco che ho inciampato intorno al 1985, e l'ho re-implementato in varie lingue più volte di quanto possa ricordare.

    
risposta data 07.12.2010 - 23:43
fonte
1

Ho scoperto che stavo scrivendo molto dello stesso codice in django, fai questa cosa comune, poi questa cosa comune e infine quella cosa comune. Prendi in genere uno o più elementi dal database o salva i risultati di un modulo.

Se ognuna di queste cose si verifica solo una volta in una vista, allora posso usare le viste generiche di django. Sfortunatamente, quelli non sono veramente componibili e ho dovuto fare diverse cose in sequenza.

Così sono andato a scrivere una libreria di viste ancora più generica, una che ha funzionato prima creando un elenco di azioni da querysets rilevanti (o qualsiasi altra cosa), e poi ha avvolto l'elenco in una vista.

Devo ancora scrivere alcune visualizzazioni a mano, ma di solito sono abbastanza complesse che non c'è molto che sia riusabile in esse. Tutto il boilerplate atterra solo altrove, sia come vista generica, sia come decoratore di vedute (spesso una vista generica decorata). Questo in genere finisce per rappresentare circa il 10% dei gestori che scrivo, dal momento che alcuni gestori generici possono fare tutto il resto.

    
risposta data 08.12.2010 - 08:19
fonte
1

Sì, ma solo per le strutture degli idiomi specifici del dominio (come i contenitori specifici degli oggetti di gioco).

Essendo semplici strumenti di utilità di qualsiasi complessità, non sono orgoglioso di nulla. Sono comunque l'unico utente al momento, quindi non c'è nulla di cui essere orgogliosi.

    
risposta data 08.12.2010 - 09:58
fonte
1

Ordinamento indiretto C ++, basato su STL sort e un modello di functor.

La necessità di un ordinamento indiretto (in cui l'output desiderato era indici di permutazione che risulterebbe dall'ordinamento dei dati, ma non i dati ordinati stesso) apparve molte volte in un certo numero di progetti. Mi sono sempre chiesto perché STL non ha fornito un'implementazione per questo.

Un altro era un vettore ciclico C ++, dove gli indici positivi e negativi sono modulo con la dimensione vettoriale (in modo che tutti i valori interi siano indici validi per il vettore).

    
risposta data 09.12.2010 - 08:58
fonte
-4

Ho scritto un piccolo pacchetto utils quando stavo sviluppando Java nel mio Comp. Lezione di sci alle superiori. Sono molto orgoglioso del mio generatore di numeri casuali.

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

Puntelli alla mia ispirazione

    
risposta data 07.12.2010 - 17:30
fonte

Leggi altre domande sui tag