У вас є власна бібліотека "різноманітні утиліти"? Якою частиною ви найбільше пишаєтесь? [зачинено]


32

Я знаю, що багато хто з нас підтримують свою маленьку особисту бібліотеку з інструментами та утилітами, якими ми користуємося часто.

Я мав своє, коли мені було 16 років, тому він виріс до значних розмірів. Деякі речі, які я написав, з тих пір були додані в рамки. Я написав власну невелику реалізацію дерев експресії для використання з генетичними алгоритмами задовго до LINQ, що мені дуже подобається і пишався в той час - звичайно, його зараз досить марно. Але останнім часом я пережив це і перейшов на .NET 4.0 і знову розпалив інтерес.

Тож мені цікаво, для чого ви використовуєте свою бібліотеку. Можливо, ми зможемо отримати кілька цікавих ідей, що стосуються маленьких корисних фрагментів, і поділитися ними між собою.

Тому мої запитання:

  • Чи є у вас різноманітна бібліотека утиліт?
  • Якою частиною ви найбільше пишаєтесь і чому?

Надайте приклад коду, якщо вам подобається :-)


Здається, ніхто не підтримує відповіді ...
Джої Адамс

@Joey Adams Так? В даний час 17 питання голосів і 6 всього голосів відповіді.
Ніколь

Я не дуже бачу відповіді, які варто підкріпити. Що означає нагорода для них? Характер запитання такий, що відповіді просто отримують "о. Приємно". якась реакція, і тоді це або підтримує все, або взагалі нічого. (І мені не подобається оскаржувати кожну відповідь, тому що вона там є. Якщо нічого іншого, я не маю голосів.: P)
Адам Лір

@Anna Lear, нормально, ви вибачили :)
Ніколь

3
Будь-яка гідна утиліта повинна бути розміщена на github та поділитися зі світом. Немає сенсу тримати його прихованим, якщо це справді добре.
Робота

Відповіді:


27

Ні.

Я бачив деякі кошмарні ефекти десятків розробників, які додають до своїх власних маленьких бібліотек стилів "util.h" до проектів, і це перетворюється на гігантський безлад непослідовних імен і функцій. Так само, як PHP. Тож з цієї причини я уникаю цього робити.

Мені не доводиться це робити, використовуючи програми програмування, які дають мені майже всі інструменти та бібліотеки, які мені потрібні вперед, коли це можливо, наприклад, C # і python.


7
Я постійно переписую свою бібліотеку в організаційних цілях.
Maxpm

3
Випадки, коли пакет комунальних послуг перетворився на кошмарний не означає, що все погано. Я не бачу, як ви можете цього уникнути і не мати більше дублювання коду через це. А отже, гірше тестування та менша ефективність.
Ніколь

2
@ Renesis: Пакети утилітів настільки ж згубні, як і goto заяви. Звичайно, саме по собі це не все так погано, але це, здавалося б, завжди рано чи пізно закінчується катастрофою. Що стосується дублювання коду, якщо ви виявляєте, що робите якесь подібне завдання практично у всіх своїх проектах, то для чогось, наприклад, python або C #, інші люди, мабуть, робили це теж, і це, мабуть, у стандартних бібліотеках до цього часу.
whatsisname

6
На мій досвід, інженери, які мають власну бібліотеку, віддадуть перевагу використанню її до того, що надається системою, тому не є доброю практикою мати особисті бібліотеки. Я колись мав хлопця, який був абсолютно впевнений, що його "strlen" функція швидша, ніж передбачена компілятором, тому що він її написав . Він провів демонстрацію того, наскільки strlen - це пара вкладених інструкцій зі складання, щоб визнати, що, можливо, інші люди можуть зробити краще.
JBRWilkinson

4
@JBRWilkinson Ваша думка добре. Не кожен програміст підходить розробляти загальний код.
Ніколь

15

SmartFormat

Моя улюблена утиліта - одна, яку я написав - простий конструктор рядків / форматів, який дозволяє дуже просто перетворити дані в рядки з правильною граматикою.

Наприклад, більшість програмістів створити текст з шаблону: "There are {0} items remaining" але це призводить до граматичних помилок: "There are 1 items remaining".

Так, SmartFormat дозволяє писати: "There {0:is|are} {0} item{0:|s} remaining".

Ви просто замінити String.Format(...)з Smart.Format(...)і ось воно!

Код SmartFormat є відкритим кодом: http://github.com/scottrippey/SmartFormat/wiki


Це нагадує мені формат, який використовує java.text.MessageFormat.
barjak

@barjak Цікаво! Я довго проводив дослідження "умовного" форматування, і ніколи не знайшов нічого подібного до цього часу! MessageFormatмає ChoiceFormatклас, який дозволяє НАДУВАТИ подібний синтаксис! Приклад з документації: "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.". Дякуємо, що згадали про це посилання.
Скотт Ріппі

@barjak Однак для підтвердження моєї точки зору, SmartFormat має ще багато можливостей! Умовне форматування працює для будь-якого типу даних, таких як bool, дата, проміжок часу та об’єкт; він також підтримує просунутих операторів, таких як "{Count:<0?negative|=5?five|>50&<100?large|other}". Він має відображення (тобто "There are {items.Length} items"може форматувати елементи масиву та часові рамки. Крім того, у нього є плагін для підтримки ще більше функцій.
Scott Rippey

Це, здається, є потужним. Форматування масивів викликає заперечення.
barjak

@barjak: Так, форматування масиву дуже корисно! Ознайомтеся з цим прикладом: Smart.Format("There are {0.Count} files: {0:'{}'|, |, and }.", files);це призведе до "There are 3 files: 'a.txt', 'b.txt', and 'c.txt'.". Я не уявляю "локалізацію" без цього.
Скотт Ріппі

7

K Комбінатор (C #, Scala)

Я використовую комбінатор K у Ruby досить часто, в основному в складках, коли операція складання виконується через побічний ефект, а не зворотне значення, як у цьому прикладі:

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

Це підраховує, як часто кожен елемент зустрічається some_collection . На жаль, це насправді не працює, оскільки блок повинен повертати нове значення акумулятора при кожній ітерації, але в Ruby присвоєння оцінюють до призначеного значення.

Отже, ви повинні явно повернути нове значення акумулятора так:

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

Але я вважаю таке явне послідовне потворне в цьому функціонально-іш стилі, використовуючи складки. K-комбінатор (покликаний Object#tapу Рубі) на допомогу:

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

Я вже кілька разів пропускав це в C # (здебільшого тому, що чомусь колекціонуючі мутатори, такі як List.Addreturn voidзамість this), і Scala, тому я займаюся цим:

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

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

Функція ідентичності (Ruby)

Щось мені не вистачає в Ruby, це добре названий спосіб доступу до функції ідентичності. Haskell надає функцію ідентичності під іменем id, Scala під іменем identity. Це дозволяє писати код на зразок:

someCollection.groupBy(identity)

Еквівалент у Ruby є

some_collection.group_by {|x| x }

Це точно не скочує язика, чи не так?

Виправлення є

IDENTITY = -> x { x }

some_collection.group_by(&IDENTITY)

ForEach (.NET)

Ще один гостро відсутній метод у 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
Я думаю, що ваш останній приклад був обчисленим дизайнерським рішенням. Поняття Actionпередбачає побічні ефекти, що суперечить принципам дизайну LINQ.
ChaosPandion

1
@ChaosPandion: Що це стосується LINQ?
Йорг W Міттаг

@ Jörg W Mittag - IEnumerableРозширення додано для LINQ.
ChaosPandion

2
@ChaosPandion: Я все ще не розумію. ForEachне є оператором LINQ. Чому повинні застосовуватися обмеження, які стосуються лише операторів LINQ ForEach, а це не оператор LINQ? І чому побічні ефекти заборонені, IEnumerable.ForEachале дозволені List.ForEach? Крім того, чому заборонені побічні ефекти заборонені, IEnumerable.ForEachале дозволені foreach?
Йорг W Міттаг

@ Jörg W Mittag - Що я говорю, це те, що його не вистачає у розширеннях, було дизайнерським рішенням. Той факт, що List<T>має ForEachрозумний характер, враховує, що це мутаційний тип.
ChaosPandion

6

У мене конвертер типів Java. Він має публічний підпис

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

і він робить все можливе, щоб перетворити вихідне значення в тип призначення. Це по суті дозволяє вам робити динамічне введення тексту в мові статично введеної :-)

Це насправді корисно для цифрових типів, розміщених у коробці. Як дратує те, що ти не можеш поставити Integerтуди, де Longочікується? Немає проблем, просто конвертуйте його. Або що, якщо ваша функція очікує double, але ви маєте nullпоставити там? Кабум, NPE. Але покладіть його convert, і ви отримаєте NaN.


Цікаве рішення. Я завжди думав, що Лонг повинен розширити цілість. Але навіть тоді у вас все ще буде проблема з автобоксингом (наскільки я знаю, немає можливості, щоб автобокс працював із спадщиною). Також +1 для NaNпідтримки.
Ніколь

NaNвідмінна. Шкода, що для цілих чисел такого немає. Я використовував Integer.MIN_VALUEяк умову. Зазвичай це "досить дивно", щоб його помітили, на відміну від значення за замовчуванням 0. Я не знаю, чому автоматичний (не) бокс не вважається (Double) nullтаким NaN. Це очевидно правильне рішення, ІМХО.
Joonas Pulakaka

6

З написаного різного коду, більшість хороших матеріалів зараз є в CCAN , а решта я прагну знайти кращі версії існуючих проектів з відкритим кодом. Сьогодні я вважаю, що пишу все менше і менше коду загального призначення на "різне", на користь написання варіантів такого коду для конкретних програм або написання модулів загального призначення, які я можу випустити самостійно.

С

Ось функція та typedef я використовував не раз. Для додатків, які потребують часу, важко перемогти мілісекунди з точки зору простоти:

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

І ще різні функції C, які я, як правило, використовую знову і знову (і знову):

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

Хаскелл

nub :: (Eq a) => [a] -> [a]Функцією Haskell є O (n²), оскільки за його підписом типу можна перевірити лише два рівні елементи. Проста альтернатива O (n log n) є map head . group . sort, але вона вимагає примусити весь список вхідних даних, перш ніж виробляти вихід, тоді як nubможна починати виробляти вихід відразу. Далі наведено альтернативу O (n log n), nubяка збирає вже побачені елементи у 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)

У Haskell, я використовую альтернативи sequence, mapM, forM, replicateM, і filterM. Кожні ці дії генерують список, але список не може бути використаний, поки дія не завершиться повністю (якщо ви використовуєте сувору монаду, як IO). Альтернативи будують список навпаки, а не формують вежу гронів, що, за результатами бенчмаркінгу, я виявився швидшим, принаймні, з 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')

Примітка: sequence_, mapM_, forM_, і replicateM_функція по - , як і раніше кращий вибір , якщо ви не зацікавлені в списку результатів.


+1 для CCAN, хоча мене можна вважати трохи упередженим :)
Tim Post

4

Я закінчую реалізацію спліт / приєднання ala Perl мовами, які цього не мають.

Я також повторно реалізовував atoi та itoa в C більше разів, ніж я хочу подумати (вбудована система сміття).


4

Ні.

Більшу частину кодування я роблю на Java, і найкраща практика - повторне використання «утилітів» з бібліотек Apache Commons та подібних проектів.

Якщо ви щодо цього об'єктивні, є мало випадків, коли ваша власна колекція «утиліт» стане суттєвим поліпшенням того, що вже зробили інші. І якщо це не поліпшення, то, можливо, ваша бібліотека утиліт - це марна трата часу на розробку та неприємність / тягар для майбутніх користувачів.


3

У мене були деякі маніпуляції з датою, які я виконував за допомогою Java, тоді я почав використовувати JodaTime, так як почув про це хороші речі і про те, чи потрібно включати в Java 7 (не впевнений, чи все ще так, але навіть якщо це не так, як і раніше варто використовувати це імхо).

Він перетворив клас 50+ лінії в одну лінію з приблизно трьома ланцюговими викликами методу.

Для допитливих це включало отримання дати за кожен день минулих п яти тижнів: наприклад, показник продажів понеділка 10 тижнів тому тощо тощо).

І ось її частина

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

Java має методи розширення?
Кугель

ні, але я думаю, що це може отримати їх у версії 7
NimChimpsky

2

У мене завжди є якийсь utilsпакет, навіть на Java, але моя колекція утиліт PHP є найбільш повторно використаною. На Яві так багато хороших бібліотек, що я або вже маю бібліотеку, включену в проект, або потрібно просто самостійно спроектувати кілька відсутніх утиліт. Бібліотеки PHP, як правило, роблять занадто багато для мене, щоб хотіти включати їх у свої проекти.

Мені подобається ця функція для PHP, вдосконалена за допомогою 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;
}

Він схожий на BeanUtils Apache для Java, і я використовую його з подібною метою, надаючи елементам форми в мові шаблону єдиний ключ, який може отримати / встановити вкладене значення у вихідному масиві:

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

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

Звичайно, будучи PHP, я хотів би зберегти метод якомога більше так що це не зовсім так , як BeanUtils функціональний;)


2

У стандартній бібліотеці Scala відсутні деякі найбільш часто використовувані функції вищого порядку.

Дві такі функції, які мені найчастіше потрібні:

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

Наразі ні. У мене був такий, коли я робив C, але тепер, коли я роблю Java, це вже не має сенсу, враховуючи всі наявні стандартні лайби, а також усі смаколики, що надходять від проекту Apache.

Однією з корисних речей у моєму конвеєрі C була швидка та брудна реалізація машини з кінцевим станом, яка дозволила визначити машину з кінцевим станом із лише двома рядками та масивом рядків. Він може бути використаний для перевірки рядків на правила (наприклад, "має бути довжиною 4..6 символів, спочатку одна літера, інші цифри"), але наявність реджексів зробила цю річ абсолютно безглуздою.



1

Я виявив, що пишу багато одного і того ж коду в джанго. Зробіть це спільне, потім це звичайне, і, нарешті, це спільне. В основному отримуйте один або кілька елементів із бази даних або зберігайте результати форми.

Якщо кожна з цих речей трапляється один раз у полі зору, я можу використовувати загальні погляди на джанго. На жаль, вони насправді не є композиційними, і мені потрібно було робити кілька речей послідовно.

Тож я пішов і написав ще більш загальну бібліотеку поглядів - ту, яка працювала, спершу створивши список дій із відповідних наборів запитів (чи що завгодно), а потім загорнула список у подання.

Мені все одно доводиться писати деякі погляди вручну, але вони, як правило, досить складні, що в них не так багато, що можна використовувати повторно. Вся плита котла просто висаджується в іншому місці, або як загальний вигляд, або як декоратор виду (часто це прикрашений загальний вигляд). Зазвичай це складає близько 10% оброблюваних вами обробників, оскільки деякі загальні обробники можуть робити все інше.


1

Так, але лише для ідіомних структур, характерних для домену (наприклад, контейнерів, характерних для ігор).

Оскільки це прості корисні інструменти, ніж що-небудь складне, я нічим там не пишаюся. Наразі я є унікальним користувачем, тому пишатися є чим.


1

Непряме сортування C ++ на основі sortшаблону STL та шаблону функтора.

Потреба в непрямому сортуванні (у якому бажаним результатом були індекси перестановки, які були б результатом сортування даних, але не відсортованих даних ), неодноразово виникала у ряді проектів. Мені завжди було цікаво, чому STL не надає для цього реалізацію.

Іншим був циклічний вектор С ++, де позитивні та негативні індекси є модулем з розміром вектора (так що будь-які цілі значення є дійсними індексами для вектора).


-4

Я написав невеликий пакет утиліт, коли я займався розробкою Java у своєму Comp. Науковий клас у середній школі. Я найбільше пишаюся своїм генератором випадкових чисел.

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

Підтримує моє натхнення.


12
c'mon, xkcd ....
Darknight

2
Давай, це не має значення.
Джош К

1
З вашими поточними голосами в -2, я здогадуюсь, це насправді має значення ...
user7676

8
Плагіат - це найвища форма лестощів, за винятком випадків, коли це очевидно.
Maxpm

5
Ну а кнопка знищення говорить: "Ця відповідь не корисна". Напевно, потрібна додаткова кнопка: "... але впевнено, що смішно"
skajfes
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.