У вас есть собственная библиотека 'misc utils'? Какой частью вы больше всего гордитесь? [закрыто]

32

Я знаю, что многие из нас имеют собственную небольшую личную библиотеку с инструментами и утилитами, которые мы часто используем.

У меня была моя с 16 лет, так что она выросла до довольно значительных размеров. Некоторые вещи, которые я написал, были добавлены в фреймворк. Я написал свою небольшую реализацию деревьев выражений для использования с генетическими алгоритмами задолго до LINQ, что мне очень нравилось и которым я гордился в то время - конечно, сейчас это довольно бесполезно. Но недавно я прошел через это и обновил до .NET 4.0 и снова зажег интерес.

Поэтому мне любопытно, для чего вы используете свою библиотеку. Возможно, мы могли бы получить некоторые интересные идеи для полезных маленьких фрагментов и поделиться ими между собой.

Итак, мои вопросы:

  • У вас есть другая полезная библиотека?
  • Какой частью вы больше всего гордитесь и почему?

Приведите пример кода, если хотите :-)

Никто
источник
Никто, кажется, не голосует против ответов ...
Джои Адамс
@ Джои Адамс Верно? В настоящее время 17 вопрос голосов и 6 всего голосов ответа.
Николь
Я на самом деле не вижу ответов, заслуживающих одобрения. Что для них значит upvote? Характер вопроса таков, что ответы просто получают «о, приятно». такая реакция, и тогда это либо возражает, либо вообще ничего. (И я не люблю отказываться от ответа на каждый ответ, просто потому, что он есть. Если ничего другого, у меня нет голосов.: P)
Адам Лир
@ Анна Лир, хорошо, ты извинилась :)
Николь
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 Интересно! Я провел много времени, исследуя «условное» форматирование, и до сих пор не нашел ничего подобного! MessageFormatимеет ChoiceFormatкласс, который позволяет удивительно похожий синтаксис! Пример из документации: "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.". Спасибо за упоминание этой ссылки.
Скотт Риппи
@barjak Просто чтобы подтвердить мою точку зрения, SmartFormat имеет гораздо больше возможностей! Условное форматирование работает для любого типа данных, такого как bool, date, timespan и object; он также поддерживает расширенные операторы, такие как "{Count:<0?negative|=5?five|>50&<100?large|other}". Он имеет отражение (то есть "There are {items.Length} items"может форматировать элементы массива и временные области. Плюс, у него есть модель плагинов для поддержки еще большего количества функций.
Скотт Риппи,
Кажется, это действительно мощно. Форматирование массивов интересное.
Барджак
@barjak: Да, форматирование массива действительно полезно! Проверьте этот пример: Smart.Format("There are {0.Count} files: {0:'{}'|, |, and }.", files);приведет к "There are 3 files: 'a.txt', 'b.txt', and 'c.txt'.". Я не могу представить себе «локализацию» без нее.
Скотт Риппи
7

K Combinator (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в Ruby) на помощь:

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

и в Скале:

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?
Йорг Миттаг
@ Jörg W Mittag - Добавлены IEnumerableрасширения для LINQ.
ChaosPandion
2
@ChaosPandion: я все еще не понимаю. ForEachне является оператором LINQ. Почему должны применяться ограничения, которые применяются только к операторам LINQ ForEach, которые не являются операторами LINQ? И почему побочные эффекты запрещены, IEnumerable.ForEachно разрешены List.ForEach? Кроме того, почему побочные эффекты запрещены, IEnumerable.ForEachно разрешены foreach?
Йорг Миттаг
@ 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.

Joonas Pulakka
источник
Интересное решение. Я всегда думал, что Long должен расширять Integer. Но даже тогда у вас все еще будет проблема с автобоксом (насколько я знаю, автобокс не будет работать с наследованием). Также +1 за NaNподдержку.
Николь
NaNотлично. Жаль, что нет такой вещи для целых чисел. Я использовал Integer.MIN_VALUEкак соглашение. Обычно это «достаточно странно», чтобы заметить, в отличие от значения по умолчанию 0. Я не знаю, почему автоматический (un) бокс не обрабатывается (Double) nullкак NaN. Это очевидное правильное решение, ИМХО.
Joonas Pulakka
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;
        }
    }
}

Haskell

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, хотя меня можно считать немного предвзятым :)
Тим Пост
4

Я заканчиваю реализацию split / join ala Perl на языках, в которых его нет.

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

Пол Натан
источник
4

Нет.

Я делаю большую часть своего кодирования на Java, и лучшая практика - это повторное использование "utils" из библиотек Apache Commons и подобных проектов.

Если вы объективны в этом, есть несколько случаев, когда ваша собственная коллекция утилит будет значительным улучшением того, что уже сделали другие люди. И если это не улучшение, то ваша библиотека утилит, вероятно, является пустой тратой времени на разработку и неудобством для будущих сопровождающих.

Стивен С
источник
3

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

Класс из 50+ строк превратился в одну строку с тремя вызовами методов.

Для любопытных это включало получение даты для каждого дня из n прошедших недель: например, цифры продаж за понедельник 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 используется чаще всего. В Java так много хороших библиотек, что у меня уже есть библиотека, включенная в проект, или мне нужно просто спроектировать несколько недостающих утилит самостоятельно. Библиотеки 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;
}

Он похож на Apache BeanUtils для 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)
}
missingfaktor
источник
1

В данный момент нет. У меня был один, когда я делал C, но теперь, когда я делаю Java, он больше не имеет смысла, учитывая все доступные стандартные библиотеки плюс все вкусности, полученные в проекте Apache.

Одной из полезных вещей в моей C lib была быстрая и грязная реализация конечного автомата, которая позволила определить конечный автомат с двумя строками и массивом строк. Его можно использовать для проверки строк на соответствие правилам (например, «должно быть длиной 4,6 символа, сначала одна буква, остальные цифры»), но наличие регулярных выражений делает эту вещь совершенно бессмысленной.

user281377
источник
1

Я обнаружил, что я пишу много одного и того же кода в django: делайте это как обычно, потом так, и, наконец, так часто. Обычно получают один или несколько элементов из базы данных или сохраняют результаты формы.

Если каждая из этих вещей происходит только один раз в представлении, тогда я могу использовать общие представления django. К сожалению, они не являются действительно составными, и мне нужно было сделать несколько вещей в последовательности.

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

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

SingleNegationElimination
источник
1

Да, но только для специфичных для предметной области структур идиом (таких как контейнеры для игровых объектов).

Поскольку это простые утилиты, а не что-то сложное, я не горжусь ничем там. Во всяком случае, я пока единственный пользователь, поэтому гордиться нечем.

Klaim
источник
1

C ++ косвенная сортировка, основанная на STL sortи шаблоне функтора.

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

Другим был циклический вектор C ++, где положительные и отрицательные индексы модулируются по размеру вектора (так что любые целочисленные значения являются действительными индексами для вектора).

rwong
источник
-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
давай, xkcd ....
Темная ночь
2
Да ладно, это не имеет значения.
Джош К
1
С твоими текущими голосами в -2, я предполагаю, что это действительно имеет значение ...
user7676
8
Плагиат является высшей формой лести, кроме случаев, когда это очевидно.
Maxpm
5
Ну, кнопка понижения говорит: «Этот ответ бесполезен». Я предполагаю, что есть необходимость в дополнительной кнопке: "... но это, конечно, смешно"
skajfes