私たちの多くは、頻繁に使用するツールとユーティリティを備えた小さな個人用ライブラリを維持していることを知っています。
私は16歳のときから私の物を持っているので、かなりのサイズに成長しました。私が書いたもののいくつかは、それ以来フレームワークに追加されました。私はLINQよりずっと前に、遺伝的アルゴリズムで使用するために独自の表現ツリーの小さな実装を作成しました。これは、当時とても気に入っていて誇りに思っていました。もちろん、今ではかなり役に立たないのです。しかし、最近私はそれを経験し、.NET 4.0にアップグレードして興味を再燃させました。
だから、私はあなたがあなたのライブラリを何のために使うのか興味があります。たぶん、便利な小さなスニペットに向けていくつかのクールなアイデアを得て、それらを自分たちで共有することができます。
だから私の質問は:
必要に応じて、コードの例を挙げてください:-)
番号。
私は何十人もの開発者が独自の小さな "util.h"スタイルライブラリをプロジェクトに追加するという悪夢のような影響を見てきました。そして、それは一貫性のない関数の命名と動作の巨大な混乱に変わります。 PHPによく似ています。だからその理由で私はそれをするのを避けます。
C#やpythonなど、可能な限り前もって必要なほぼすべてのツールとライブラリを提供するプログラミング環境を使用することで、その必要はありません。
私のお気に入りのユーティリティは、私が書いたものです。データを正しい文法で文字列に本当に簡単に変換できるシンプルな文字列ビルダー/フォーマッターです。
たとえば、ほとんどのプログラマーはテンプレートからテキストを作成します:_"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
私はRubyでKコンビネーターを頻繁に使用します。この例のように、折り返し操作が戻り値ではなく副作用によって実行される場合、ほとんどの場合は折り返しで使用します。
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コンビネーター(RubyではObject#tap
と呼ばれます)が救い出します:
some_collection.reduce(Hash.new(0)) {|acc, el| acc.tap { acc[el] += 1 }}
私はすでにC#(いくつかの理由でList.Add
などのコレクションミューテーターが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で欠けているものは、識別関数にアクセスするためのわかりやすい名前の付いた方法です。 Haskellはid
という名前の識別関数を提供しますScala identity
という名前のもとです。これにより、次のようなコードを書くことができます。
someCollection.groupBy(identity)
Rubyで同等のものは
some_collection.group_by {|x| x }
舌から正確に転がるのではないですか?
修正は
IDENTITY = -> x { x }
some_collection.group_by(&IDENTITY)
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);
}
}
}
私が書いたその他のコードのうち、良いもののほとんどは [〜#〜] ccan [〜#〜] にありますが、残りは既存のオープンソースでより良いバージョンを見つける傾向がありますプロジェクト。最近では、そのようなコードのアプリケーション固有のバリアントを記述したり、自分でリリースできる汎用モジュールを記述したりすることに賛成して、ますます汎用性の低い「その他の」コードを記述しています。
これは、私が2回以上使用した関数と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²)です。これは、その型シグネチャによって、2つの要素が等しいかどうかをテストすることしかできないためです。単純なO(n log n)の代替案は_map head . group . sort
_ですが、出力を生成する前に入力リスト全体を強制する必要がありますが、nub
はすぐに出力の生成を開始できます。以下は、すでに表示されている項目を_Data.Set
_に収集するnub
のO(n log n)の代替です。
_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_
_関数を使用することをお勧めします。
Java Type Converterがあります。公開署名があります
public static <T> T convert(Object sourceValue, Class<T> destinationType)
そして、ソース値を宛先タイプに変換することが最善です。本質的に、静的型付け言語内で動的型付けを行うことができます:-)
これは、ボックス化された数値型で実際に役立ちます。 Integer
をLong
が期待される場所に置くことができないのはどのようにイライラしますか?問題ありません。変換してください。または、関数がdouble
を期待しているが、そこにnull
を置く場合はどうなりますか? NPEのカブーム。しかし、それをconvert
に入れると、NaN
が得られます。
Perlを持たない言語で、Perlの分割/結合を実装する必要があります。
また、atoiとitoaをCで何度も再実装しました(組み込みシステムのジャンク)。
番号。
私はほとんどのコーディングをJavaで行っています。ベストプラクティスは、Apache Commonsライブラリや類似のプロジェクトの「utils」を再利用することです。
あなたがそれについて客観的であるならば、あなた自身の「utils」コレクションが他の人々がすでに行ったことを大幅に改善するケースはほとんどありません。そしてそれが改善されていない場合、あなたのutilsライブラリはおそらく開発時間の浪費であり、将来のメンテナにとって厄介な/負担となります。
Javaを使用して実行したいくつかの日付操作があり、それについて JodaTime の使用を開始しました。これは、それについて良いことを聞き、Java 7(これがまだ当てはまるかどうか確認してください。ただし、そうでない場合でも、それを使用する価値は十分にあります)。
これにより、50以上の行クラスが1つの行になり、約3つのチェーンされたメソッド呼び出しが行われました。
好奇心が強い人には、n週間前の毎日の日付を取得する必要がありました。たとえば、10週間前の月曜日の売上高などです。
そして、これはその一部です
public static DateTime getDayPreviousWeek(DateTime dt, DayOfWeek dayOfWeek, int n_weeks) {
return dt.minusWeeks(n_weeks).dayOfWeek().setCopy(dayOfWeek.getDayAsString());
}
私はJavaであっても常にutils
パッケージを持っていますが、私の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;
}
これは、ApacheのJavaのBeanUtilsに似ており、テンプレート言語のフォーム要素に、ソース配列内のネストされた値を取得/設定できる単一のキーを与えて、同様の目的で使用します。
$source = array('a' => array('b' => 5));
$val = getValueFromDotKey($source, 'a.b');
もちろん、PHPなので、メソッドをできるだけ軽量にしたかったので、BeanUtils ;)
ほど機能的ではありませんかなり
Scala標準ライブラリには、最も一般的に使用される高次関数がいくつかありません。
私が最も頻繁に必要とするそのような2つの関数:
// #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)
}
STL sort
およびファンクターテンプレートに基づくC++間接ソート。
間接的な並べ替えの必要性(目的の出力は順列インデックスであり、データの並べ替えの結果であり、-sorted data自体ではない)が何度も出現したプロジェクトの。なぜSTLがその実装を提供していないのかといつも疑問に思いました。
もう1つはC++循環ベクトルで、正と負のインデックスはベクトルサイズのモジュロです(整数値がベクトルの有効なインデックスになるように)。
現在、ありません。 Cをやっていたときに1つ持っていましたが、Javaをやっているので、すべての標準ライブラリとApacheプロジェクトから来るすべての便利さを考えると、もはや意味がありません。
私のC libの便利な点の1つは、高速でダーティな有限状態マシンの実装でした。これにより、2つの文字列と文字列の配列だけで有限状態マシンを定義できました。ルールに照らして文字列をチェックするために使用できます(たとえば、「4..6文字である必要があり、最初の文字が文字で、残りの数字が必要です」)。
私はDjangoで同じコードをたくさん書いていることに気付きました。この一般的なことを行い、次にこの一般的なことを行い、最後にその一般的なことを行いました。基本的に、データベースから1つ以上のアイテムを取得するか、フォームの結果を保存します。
これらのすべてがビューで1回だけ発生する場合、Django汎用ビューを使用できます。残念ながら、これらは実際には構成可能ではなく、いくつかのことを順番に実行する必要がありました。
そこで、さらに一般的なビューライブラリを作成しました。これは、まず関連するクエリセット(またはその他)からアクションのリストを作成し、リストをビューにラップすることで機能しました。
私はまだいくつかのビューを手作業で書く必要がありますが、これらは通常、再利用可能なものがあまりないほど複雑です。すべてのボイラープレートは、汎用ビュー、またはビューデコレータ(装飾された汎用ビューの場合が多い)として他の場所に配置されるだけです。一部の汎用ハンドラーが他のすべてを実行できるため、これは通常、私が作成するハンドラーの約10%になります。
はい。ただし、ドメイン固有のイディオム構造(ゲームオブジェクト固有のコンテナーなど)の場合のみです。
複雑なものよりもシンプルなユーティリティツールなので、私はそこに何も誇りに思いません。とにかく私は今のところ唯一のユーザーなので、誇りに思うことは何もありません。