Czy masz własną bibliotekę „misc utils”? Z jakiej części jesteś najbardziej dumny? [Zamknięte]


32

Wiem, że wielu z nas prowadzi własną bibliotekę osobistą z narzędziami i narzędziami, z których często korzystamy.

Miałem swój odkąd miałem 16 lat, więc urósł do całkiem sporych rozmiarów. Niektóre rzeczy, które napisałem, zostały dodane do frameworka. Napisałem własną małą implementację drzewek ekspresyjnych do użycia z algorytmami genetycznymi na długo przed LINQ, co bardzo mi się podobało i z czego byłem dumny - oczywiście teraz jest całkiem bezużyteczne. Ale ostatnio przeszedłem przez to i uaktualniłem do .NET 4.0 i ponownie wzbudziłem zainteresowanie.

Jestem więc ciekawy, do czego używasz swojej biblioteki. Może moglibyśmy znaleźć fajne pomysły na przydatne małe fragmenty i podzielić się nimi między sobą.

Więc moje pytania to:

  • Czy masz różne biblioteki narzędzi?
  • Z której części jesteś najbardziej dumny i dlaczego?

Podaj przykład kodu, jeśli chcesz :-)


Wydaje się, że nikt nie aprobuje odpowiedzi ...
Joey Adams,

@Joey Adams, prawda? Obecnie 17 głosów na pytania i 6 głosów z odpowiedzią całkowitą .
Nicole,

Naprawdę nie widzę odpowiedzi wartych poprawy. Co dla nich oznacza głosowanie? Charakter pytania jest taki, że odpowiedzi stają się „och. Fajne”. rodzaj reakcji, a wtedy albo głosuje na wszystko, albo wcale. (I nie lubię głosować na każdą odpowiedź tylko dlatego, że tam jest. Jeśli nic innego, nie mam głosów.: P)
Adam Lear

@Anna Lear, ok, przepraszam :)
Nicole

3
Wszelkie przyzwoite narzędzia powinny być udostępniane na github i udostępniane światu. Nie ma sensu ukrywać go, jeśli jest naprawdę dobry.
Job

Odpowiedzi:


27

Nie.

Widziałem koszmarne efekty kilkunastu programistów, którzy dodawali do projektów własne małe biblioteki w stylu „util.h” i zamieniali się w gigantyczny bałagan niespójnych nazw i zachowań funkcji. Podobnie jak PHP. Z tego powodu unikam tego.

Unikam potrzeby robienia tego, używając środowisk programistycznych, które dają mi prawie wszystkie narzędzia i biblioteki, których potrzebuję z góry, gdy tylko jest to możliwe, takie jak C # i python.


7
Ciągle przepisuję bibliotekę w celach organizacyjnych.
Maks.

3
Przypadki, w których pakiet utils stał się koszmarny, nie oznacza, że ​​wszystkie są złe. Nie widzę, jak można tego uniknąć i nie ma z tego powodu więcej duplikacji kodu. A zatem gorsze testy i mniejsza wydajność.
Nicole,

2
@Reneesis: Pakiety utils są tak katastrofalne jak instrukcje goto. Oczywiście samo w sobie nie jest wcale takie złe, ale prędzej czy później po prostu zawsze kończy się katastrofą. Jeśli chodzi o powielanie kodu, jeśli znajdziesz się w podobnym zadaniu w praktycznie wszystkich swoich projektach, to w przypadku Pythona lub C # inne osoby prawdopodobnie również to robią i prawdopodobnie jest to wtedy w standardowych bibliotekach.
whatsisname

6
Z mojego doświadczenia wynika, że ​​inżynierowie z własną biblioteką będą preferować korzystanie z niej przed biblioteką systemową, więc nie jest dobrą praktyką posiadanie bibliotek osobistych. Kiedyś miałem faceta, który był absolutnie przekonany, że jego funkcja „strlen” była szybsza niż funkcja dostarczona przez kompilator, ponieważ ją napisał . Wystarczył prosty pokaz, jak strlen to kilka wbudowanych instrukcji montażu, aby przyznać, że może inni ludzie mogą to zrobić lepiej.
JBRWilkinson

4
@JBRWilkinson Twój punkt widzenia jest słuszny. Nie każdy programista jest zdolny do opracowania wspólnego kodu.
Nicole,

15

SmartFormat

Moim ulubionym narzędziem jest to, które napisałem - prosty konstruktor / formatator łańcuchów, który naprawdę ułatwia przekształcanie danych w łańcuchy o poprawnej gramatyce.

Na przykład, większość programistów budować tekst z szablonu: "There are {0} items remaining" Ale to prowadzi do błędów gramatycznych: "There are 1 items remaining".

Więc SmartFormat pozwala napisać: "There {0:is|are} {0} item{0:|s} remaining".

Wystarczy wymienić String.Format(...)ze Smart.Format(...)i to jest to!

SmartFormat kod jest open source: http://github.com/scottrippey/SmartFormat/wiki


To przypomina mi format używany przez java.text.MessageFormat.
barjak

@barjak Ciekawe! Długo szukałem formatowania „warunkowego” i do tej pory nie znalazłem niczego podobnego! MessageFormatma ChoiceFormatklasę, która pozwala NAJWYŻSZEJ podobnej składni! Przykład z dokumentacją: "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.". Dziękujemy za wzmiankę o tej referencji.
Scott Rippey,

@barjak Aby jednak potwierdzić moją tezę, SmartFormat ma wiele innych funkcji! Formatowanie warunkowe działa dla dowolnego typu danych, takiego jak bool, data, przedział czasowy i obiekt; obsługuje również zaawansowanych operatorów, takich jak "{Count:<0?negative|=5?five|>50&<100?large|other}". Ma odbicie (tj. "There are {items.Length} items"Może formatować elementy tablicy i przedziały czasowe. Dodatkowo ma model wtyczki do obsługi jeszcze większej liczby funkcji.
Scott Rippey

Rzeczywiście wydaje się potężny. Formatowanie tablic jest ciekawe.
barjak

@barjak: Tak, formatowanie tablicy jest naprawdę przydatne! Sprawdź ten przykład: Smart.Format("There are {0.Count} files: {0:'{}'|, |, and }.", files);spowoduje "There are 3 files: 'a.txt', 'b.txt', and 'c.txt'.". Bez tego nie wyobrażam sobie „lokalizacji”.
Scott Rippey

7

K Combinator (C #, Scala)

Używam kombinatora K w Ruby dość często, głównie podczas składania, gdy operacja składania jest wykonywana raczej przez efekt uboczny niż przez wartość zwracaną, jak w tym przykładzie:

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

To liczy, jak często występuje każdy element some_collection. Niestety, to tak naprawdę nie działa, ponieważ blok musi zwracać nową wartość akumulatora przy każdej iteracji, ale w przypisaniach Ruby ocenia się na przypisaną wartość.

Musisz więc w sposób ekscytujący zwrócić nową wartość akumulatora w następujący sposób:

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

Ale takie wyraźne sekwencjonowanie wydaje mi się brzydkie w tym funkcjonalnym stylu przy użyciu fałd. Kombinator K (nazywany Object#tapw Ruby) na ratunek:

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

Parę razy tęskniłem już w języku C # (głównie z jakiegoś powodu mutatory kolekcji, takie jak List.Addreturn voidzamiast zamiast this) i Scala, więc noszę to:

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

oraz w Scali:

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

Funkcja tożsamości (Ruby)

Coś, czego mi brakuje w Ruby, to przyjemnie nazwany sposób dostępu do funkcji tożsamości. Haskell zapewnia funkcję tożsamości pod nazwą id, Scala pod nazwą identity. Umożliwia to pisanie kodu takiego jak:

someCollection.groupBy(identity)

Odpowiednikiem w Ruby jest

some_collection.group_by {|x| x }

Czyż nie dokładnie stacza się z języka, prawda?

Poprawka jest

IDENTITY = -> x { x }

some_collection.group_by(&IDENTITY)

ForEach (.NET)

Kolejna bardzo brakująca metoda w języku 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);
        }
    }
}

3
Myślę, że twój ostatni przykład był obliczoną decyzją projektową. Koncepcja Actionimplikuje skutki uboczne, które są sprzeczne z zasadami projektowania LINQ.
ChaosPandion,

1
@ChaosPandion: Co to ma wspólnego z LINQ?
Jörg W Mittag,

@ Jörg W Mittag - IEnumerableRozszerzenia zostały dodane dla LINQ.
ChaosPandion,

2
@ChaosPandion: Nadal nie rozumiem. ForEachnie jest operatorem LINQ. Dlaczego ograniczenia, które dotyczą tylko operatorów LINQ, powinny być stosowane ForEach, a nie operator LINQ? I dlaczego efekty uboczne są zabronione, IEnumerable.ForEachale dozwolone List.ForEach? Ponadto, dlaczego efekty uboczne są zabronione, IEnumerable.ForEachale dozwolone foreach?
Jörg W Mittag,

@ Jörg W Mittag - To, co mówię, to fakt, że brakuje go w rozszerzeniach, to była decyzja projektowa. Fakt, że List<T>ma, ForEachjest uzasadniony, biorąc pod uwagę, że jest to typ zmienny.
ChaosPandion,

6

Mam konwerter typów Java. Ma podpis publiczny

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

i stara się przekonwertować wartość źródłową na typ docelowy. Zasadniczo pozwala to na dynamiczne pisanie w statycznym języku :-)

Jest to przydatne w przypadku pudełkowych typów numerycznych. Jak denerwujące jest to, że nie możesz postawić tego, Integerco Longjest oczekiwane? Nie ma problemu, wystarczy go przekonwertować. A co jeśli twoja funkcja oczekuje double, ale musisz nullją tam umieścić? Kaboom, NPE. Ale przełóż to convert, a dostaniesz NaN.


Ciekawe rozwiązanie Zawsze uważałem, że Long powinien rozszerzać liczbę całkowitą. Ale nawet wtedy nadal będziesz mieć problem z autoboxingiem (o ile wiem, nie ma możliwości, aby autoboxing działałby z dziedziczeniem). Ponadto +1 za NaNwsparcie.
Nicole,

NaNjest świetny. Szkoda, że ​​nie ma czegoś takiego dla liczb całkowitych. Użyłem Integer.MIN_VALUEjako konwencji. Zazwyczaj jest to „dość dziwne”, aby zostać zauważonym, w przeciwieństwie do domyślnej wartości 0. Nie wiem, dlaczego auto (un) boxing nie traktuje się (Double) nulltak jak NaN. To oczywiste właściwe rozwiązanie, IMHO.
Joonas Pulakka

6

Z kodu misc, który napisałem, większość dobrych rzeczy znajduje się teraz w CCAN , a resztę szukam lepszych wersji w istniejących projektach open source. W dzisiejszych czasach piszę coraz mniej ogólnego kodu „misc” na korzyść pisania wariantów takiego kodu specyficznych dla aplikacji lub pisania modułów ogólnego przeznaczenia, które mogę samodzielnie wydać.

do

Oto funkcja i typefef, którego użyłem więcej niż raz. W aplikacjach, które wymagają synchronizacji, trudno jest przekroczyć milisekundy pod względem prostoty:

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

I więcej różnych funkcji C, których używam w kółko (i więcej):

/* 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

nub :: (Eq a) => [a] -> [a]Funkcja Haskella to O (n²), ponieważ ze względu na jej podpis typu można testować tylko, czy dwa elementy są równe. Prosta alternatywa O (n log n) jest map head . group . sort, ale wymaga wymuszenia całej listy danych wejściowych przed wygenerowaniem danych wyjściowych, podczas gdy nubmożna od razu zacząć wytwarzać dane wyjściowe. Oto O (n log n) alternatywa dla nubzbierania już widocznych elementów w 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)

W Haskell, używam alternatywy dla sequence, mapM, forM, replicateM, i filterM. Każda z tych akcji generuje listę, ale listy nie można użyć, dopóki akcja nie zakończy się w całości (jeśli używasz ścisłej monady, takiej jak IO). Alternatywy budują listę w odwrotnej kolejności niż tworząc wieżę grudek, które znalazłem dzięki analizie porównawczej jako szybszej, przynajmniej w przypadku 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')

Uwaga: sequence_, mapM_, forM_, i replicateM_funkcje są jeszcze lepszym wyborem, jeśli nie jesteś zainteresowany w liście wynikowej.


+1 dla CCAN, choć można mnie uznać za nieco stronniczego :)
Tim Post

4

Kończę wdrażanie split / join ala Perl w językach, które go nie mają.

Zaimplementowałem również atoi i itoa w C więcej razy, niż chcę o tym myśleć (śmieci z systemów wbudowanych).


4

Nie.

Większość kodowania wykonuję w Javie, a najlepszą praktyką jest ponowne użycie „utils” z bibliotek Apache Commons i podobnych projektów.

Jeśli jesteś tego obiektywny, istnieje kilka przypadków, w których Twoja własna kolekcja „utils” znacząco poprawi to, co zrobili już inni ludzie. A jeśli nie jest to poprawa, to biblioteka utils jest prawdopodobnie stratą czasu na programowanie i stanowi utrapienie dla przyszłych opiekunów.


3

Miałem kilka manipulacji datą, które wykonałem przy użyciu Javy, a potem zacząłem używać JodaTime ponieważ słyszałem o nim dobre rzeczy i że powinien zostać włączony do Javy 7 (nie jestem pewien, czy tak jest nadal, ale nawet jeśli tak nie jest, nadal jest warto go używać imho).

Przekształcił klasę linii 50+ w jedną linię z około trzema połączonymi wywołaniami metod.

Dla ciekawskich wymagało to ustalenia daty dla każdego dnia n tygodni wcześniej: np. Wartość sprzedaży w poniedziałek 10 tygodni temu itp.).

A oto część tego

public static DateTime getDayPreviousWeek(DateTime dt, DayOfWeek dayOfWeek, int n_weeks) {
       return dt.minusWeeks(n_weeks).dayOfWeek().setCopy(dayOfWeek.getDayAsString());
}

java ma metody rozszerzenia?
Kugel,

nie, ale myślę, że może to być w wersji 7
NimChimpsky

2

Zawsze mam jakiś utilspakiet, nawet w Javie, ale moja kolekcja narzędzi PHP jest najczęściej używana. W Javie jest tak wiele dobrych bibliotek, że albo mam już bibliotekę zawartą w projekcie, albo muszę po prostu zaprojektować kilka brakujących narzędzi na własną rękę. Biblioteki PHP zwykle robią za dużo, aby móc je włączyć do moich projektów.

Podoba mi się ta funkcja dla PHP, dopracowana przy pomocy 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;
}

Jest podobny do BeanUtils dla Javy Apache i używam go do podobnego celu, nadając elementom formularza w języku szablonów pojedynczy klucz, który może uzyskać / ustawić wartość zagnieżdżoną w tablicy źródłowej:

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

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

Oczywiście, będąc PHP, chciałem zachować jak najlżejszą metodę, aby nie była tak funkcjonalna jak BeanUtils;)


2

Standardowej bibliotece Scali brakuje niektórych najczęściej używanych funkcji wyższego rzędu.

Dwie takie funkcje, których najczęściej potrzebuję:

// #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)
}

1

Obecnie nie. Miałem taki, kiedy robiłem C, ale teraz, gdy robię Javę, nie ma już sensu, biorąc pod uwagę wszystkie standardowe dostępne biblioteki lib, a także wszystkie gadżety pochodzące z projektu Apache.

Jedną z przydatnych rzeczy w mojej bibliotece C lib była szybka i brudna implementacja skończonej maszyny stanów, która pozwoliła zdefiniować skończoną maszynę stanów z tylko dwoma łańcuchami i tablicą ciągów. Można go używać do sprawdzania ciągów pod kątem reguł (np. „Musi mieć długość 4..6 znaków, pierwsza litera, cyfry spoczynkowe”), ale dostępność wyrażeń regularnych sprawiła, że ​​stało się to całkowicie bezcelowe.



1

Odkryłem, że piszę dużo tego samego kodu w django. Zrób to wspólne, potem to wspólne i wreszcie to wspólne. Zasadniczo pobierz jeden lub więcej elementów z bazy danych lub zapisz wyniki formularza.

Jeśli każda z tych rzeczy występuje tylko raz w widoku, mogę użyć widoków ogólnych django. Niestety, tak naprawdę nie można ich skomponować i musiałem zrobić kilka rzeczy po kolei.

Poszedłem więc i napisałem jeszcze bardziej ogólną bibliotekę widoków, która działała, najpierw budując listę akcji z odpowiednich zestawów zapytań (lub cokolwiek innego), a następnie zawinęłem listę w widok.

Nadal muszę ręcznie napisać kilka poglądów, ale zwykle są one na tyle skomplikowane, że niewiele z nich można wykorzystać. Cała płyta podstawowa po prostu ląduje gdzie indziej, albo widok ogólny, albo jako dekorator widoku (często dekorowany widok ogólny). Zwykle stanowi to około 10% programów obsługi, które piszę, ponieważ niektóre ogólne funkcje obsługi mogą zrobić wszystko inne.


1

Tak, ale tylko dla struktur idiomów specyficznych dla domeny (takich jak kontenery specyficzne dla obiektów gry).

Ponieważ są to proste narzędzia użytkowe niż cokolwiek złożonego, nie jestem z niczego dumny. W tej chwili jestem unikalnym użytkownikiem, więc nie ma się czym pochwalić.


1

Sortowanie pośrednie w C ++, oparte na STL sorti szablonie funktorów.

Potrzeba sortowania pośredniego (w którym pożądanym wynikiem były indeksy permutacji , które wynikałyby z sortowania danych, ale nie samych danych sortowanych ) pojawiła się wiele razy w wielu projektach. Zawsze zastanawiałem się, dlaczego STL nie zapewnił dla niego implementacji.

Innym był cykliczny wektor C ++, w którym indeksy dodatnie i ujemne są modulo z rozmiarem wektora (tak, że wszelkie wartości całkowite są poprawnymi indeksami dla wektora).


-4

Napisałem mały pakiet utils, gdy tworzyłem Java w moim komputerze. Klasa Sci w liceum. Jestem najbardziej dumny z mojego generatora liczb losowych.

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

Podpory do mojej inspiracji.


12
c'mon, xkcd ....
Darknight

2
No dalej, to nie ma znaczenia.
Josh K

1
Biorąc pod uwagę twoje obecne głosy na -2, wydaje mi się, że to naprawdę ma znaczenie ...
user7676

8
Plagiat jest najwyższą formą pochlebstwa, chyba że jest to oczywiste.
Maks.

5
Cóż, przycisk „w dół” mówi: „Ta odpowiedź nie jest przydatna”. Myślę, że potrzebny jest dodatkowy przycisk: „... ale na pewno jest zabawny”
skajfes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.