У вас есть собственная библиотека «misc utils»? Какую часть вы больше всего гордитесь? [закрыто]
Я знаю, что многие из нас поддерживают нашу собственную небольшую личную библиотеку с помощью инструментов и утилит, которые мы часто используем.
У меня было мое, так как мне было 16 лет, поэтому он вырос до довольно значительных размеров. С тех пор некоторые материалы, которые я написал, были добавлены в структуру. Я написал собственную небольшую реализацию деревьев выражений для использования с генетическими алгоритмами задолго до LINQ, что мне очень нравилось и гордилось в то время, конечно, сейчас оно довольно бесполезно. Но недавно я прошел через него и обновился до .NET 4.0 и повторно зажег интерес.
Так что мне любопытно, для чего вы используете свою библиотеку. Возможно, мы могли бы получить некоторые интересные идеи для полезных небольших фрагментов и поделиться ими между собой.
Итак, мои вопросы:
- У вас есть небольшая библиотека утилиты?
- Какую часть вы больше всего гордитесь и почему?
Приведите пример кода, если вам нравится :-)
16 ответов
Нет.
Я видел некоторые кошмарные эффекты от десятков разработчиков, добавляющих свои собственные маленькие библиотеки стиля «util.h» в проекты, и превратить их в гигантский беспорядок непоследовательных имен функций и поведения. Очень похоже на PHP. Поэтому по этой причине я избегаю этого.
Мне не нужно это делать, используя среды программирования, которые дают мне почти все инструменты и библиотеки, которые мне нужны, когда это возможно, например, C # и python.
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
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
в Ruby) для спасения:
some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}
Я уже пропустил это пару раз в C # (в основном потому, что по какой-то причине мутаторы коллекции, такие как List.Add
return 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);
}
}
}
У меня есть конвертер типов Java. Он имеет публичную подпись
public static <T> T convert(Object sourceValue, Class<T> destinationType)
, и он делает все возможное, чтобы преобразовать исходное значение в тип назначения. Это позволяет вам динамически печатать на статически типизированном языке: -)
Это действительно полезно с коробочными числовыми типами. Как раздражает то, что вы не можете поставить Integer
туда, где Long
ожидается? Нет проблем, просто преобразуйте его. Или что, если ваша функция ожидает double
, но у вас есть null
, чтобы положить туда? Kaboom, NPE. Но введите convert
, и вы получите NaN
Из моего кода, который я написал, большая часть хорошего материала находится в 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]
- это 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_
лучший выбор, если вы не заинтересованы в списке результатов.
Я завершаю реализацию split /join ala Perl на языках, которые его не имеют.
Я также повторно реализовал atoi и itoa в C еще раз, чем хочу думать (вложенные нежелательные системы).
Нет.
Я делаю большую часть своей кодировки на Java, и лучше всего использовать повторную утилиту из «Apache Commons» и аналогичных проектов.
Если вы объективны в этом, мало случаев, когда ваша собственная коллекция «utils» станет значительным улучшением в отношении того, что уже сделали другие люди. И если это не улучшение, то ваша библиотека utils, вероятно, является пустой тратой времени разработки и неприятностью /нагрузкой для будущих сопровождающих.
У меня были некоторые манипуляции с датами, которые я выполнял с помощью 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());
}
У меня всегда есть пакет utils
, даже в Java, но моя сборка PHP utils наиболее часто используется. В 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;
}
Он похож на BeanUtils от Apache для Java, и я использую его для аналогичной цели, предоставляя элементам формы на языке шаблона один ключ, который может получить /установить вложенное значение в исходном массиве:
$source = array('a' => array('b' => 5));
$val = getValueFromDotKey($source, 'a.b');
Конечно, будучи PHP, я хотел, чтобы этот метод был как можно более легким, поэтому он не является довольно настолько функциональным, как BeanUtils ;)
В стандартной библиотеке 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)
}
В настоящее время нет. У меня был один, когда я делал C, но теперь, когда я занимаюсь Java, это уже не имеет смысла, учитывая все доступные стандартные библиотеки, плюс все плюсы, исходящие из проекта Apache.
Одной из полезных вещей в моей C lib была реализация быстрой и конечной конечной машины, которая позволяла определять конечный конечный автомат только с двумя строками и массивом строк. Его можно использовать для проверки строк против правил (например, «должно быть длиной 4..6 символов, сначала буквы, цифры отдыха»), но доступность регулярных выражений сделала эту вещь совершенно бессмысленной.
Теперь я не могу писать пользовательские интерфейсы рабочего стола без динамических диалогов на основе
Мне показалось, что я пишу много одного и того же кода в django, делаю эту общую вещь, затем эту общую вещь и, наконец, эту общую вещь. В основном получить один или несколько элементов из базы данных или сохранить результаты формы.
Если каждая из этих вещей происходит только один раз в представлении, то я могу использовать общие представления django. К сожалению, на самом деле это не очень сложно, и мне нужно было сделать несколько вещей в последовательности.
Итак, я пошел и написал еще более общую библиотеку представлений, которая работала, сначала создавая список действий из релевантных наборов запросов (или что-то еще), а затем завернула список в представление.
Мне все же приходится писать некоторые взгляды вручную, но они обычно достаточно сложны, что в них мало что можно использовать повторно. Вся плитка просто приземляется в другом месте, либо общий вид, либо как декоратор (как правило, украшенный общий вид). Обычно это составляет около 10% обработчиков, которые я пишу, поскольку какой-то общий обработчик может делать все остальное.
Да, но только для доменных структур идиом (например, контейнеров, специфичных для игровых объектов).
Как простые утилиты, чем что-либо сложное, я ничем не горжусь. В любом случае, я единственный пользователь, поэтому вам нечем гордиться.
Косвенная сортировка C ++ на основе STL sort
и шаблон-функтор.
Необходимость косвенной сортировки (в которой желаемым результатом были индексы перестановки , которые возникли бы при сортировке данных, но не в отсортированных данных ), появлялись много раз в ряде проектов. Я всегда задавался вопросом, почему STL не предоставила ему реализацию.
Другим был циклический вектор C ++, где положительные и отрицательные индексы по модулю с размером вектора (так что любые целые значения являются действительными индексами для вектора).
Я написал небольшой пакет utils, когда занимался разработкой Java в своем Comp. Sci класс в средней школе. Я больше всего горжусь своим генератором случайных чисел.
/**
* Returns a random integer.
*
* @returns int Random integer
*/
public static int getRandom()
{
return 4; // Chosen by a fair dice roll.
// Guaranteed to be random.
}