いくつかの名前を持つ単純な配列があり、最初の文字でグループ化したいと思います。 など。最初の文字としてAからCまでのすべての名前は配列に入れられ、DからFへの名前は別の文字に移動します。レターレンジ別グループ配列要素
if elseをたくさん使うよりも良い方法がありますか?
いくつかの名前を持つ単純な配列があり、最初の文字でグループ化したいと思います。 など。最初の文字としてAからCまでのすべての名前は配列に入れられ、DからFへの名前は別の文字に移動します。レターレンジ別グループ配列要素
if elseをたくさん使うよりも良い方法がありますか?
私は現在4つの方法を提供しています。 $size
を変更することで、すべてのグループを拡大または縮小することができます。
foreach()
ループを用いてアレイ及び各値の最初の文字に比較として値を処理「ABCDEFGHIJKLMNO」、「PQRSTUVWXYZ」を作成します。これは理解するのが一番簡単です。
$fruits=array("date","guava","lemon","Orange","kiwi","Banana","apple");
natcasesort($fruits); // pre-sort them for alphabetized output
$size=3; // <-modify group sizes here
$chunks=array_chunk(range('A','Z'),$size); // 0=>["A","B","C"],1=>["D","E","F"],etc...
foreach($fruits as $fruit){
foreach($chunks as $letters){
if(in_array(strtoupper($fruit[0]),$letters)){ // check if captialized first letter exists in $letters array
$groups[implode($letters)][]=$fruit; // push value into this group
break; // go to next fruit/value
}
}
}
var_export($groups);
コード#2は、内側ループ(及びインナーループ自体)の非マッチングの繰り返しを排除するためにコード#1 apokryfos'非常に巧妙なord()
ラインを統合します。これは効率の向上をもたらしますが、可読性に悪影響を与えます。
$fruits=array("date","guava","lemon","Orange","kiwi","Banana","apple");
natcasesort($fruits); // pre-sort them for alphabetized output
$size=3; // <-modify group sizes here
$chunks=array_chunk(range('A','Z'),$size); // 0=>["A","B","C"],1=>["D","E","F"],etc...
foreach($fruits as $fruit){
$groups[implode($chunks[floor((ord(strtoupper($fruit[0]))-ord("A"))/$size)])][]=$fruit;
}
var_export($groups);
コード#3プロセスpreg_match_all()
を使用してCSV文字列として値と、いくつかのフィルタリング機能。これは、カンマが値に含まれていないことを前提としています。私の意見では、このコードは、すべての関数と非常に長い正規表現パターンのため、一見して理解するのは難しいです。
$fruits=array("date","guava","lemon","Orange","kiwi","Banana","apple");
natcasesort($fruits); // pre-sort them for alphabetized output // array(6 => 'apple',5 => 'Banana',0 => 'date',1 => 'guava',4 => 'kiwi',2 => 'lemon',3 => 'Orange')
$size=3; // <-modify group sizes here
$chunks=str_split(implode(range('A','Z')),$size); // ['ABC','DEF','GHI','JKL','MNO','PQR','STU','VWX','YZ']
$regex="/((?<=^|,)[".implode('][^,]*)|((?<=^|,)[',$chunks)."][^,]*)/i"; // '/((?<=^|,)[ABC][^,]*)|((?<=^|,)[DEF][^,]*)|((?<=^|,)[GHI][^,]*)|((?<=^|,)[JKL][^,]*)|((?<=^|,)[MNO][^,]*)|((?<=^|,)[PQR][^,]*)|((?<=^|,)[STU][^,]*)|((?<=^|,)[VWX][^,]*)|((?<=^|,)[YZ][^,]*)/i'
if(preg_match_all($regex,implode(",",$fruits),$out)){
$groups=array_map('array_values', // 0-index subarray elements
array_filter( // omit empty subarrays
array_map('array_filter', // omit empty subarray elements
array_combine($chunks, // use $chunks as keys for $out
array_slice($out,1) // remove fullstring subarray from $out
)
)
)
);
var_export($groups);
}
コード#4用いてループまたは条件式無しアレイなどのプロセス値:ワンライナーを形成するarray_map()
を、preg_grep()
をarray_values()
、array_combine()
、及びarray_filter
* $size
& $chunks
宣言を割り引きます。 ...私は1ライナーを作るまで停止したくない - どんなに醜い。 ;)
$fruits=array("date","guava","lemon","Orange","kiwi","Banana","apple");
natcasesort($fruits); // pre-sort them for alphabetized output
$size=3; // <-modify group sizes here
$chunks=str_split(implode(range('A','Z')),$size); // ['ABC','DEF','GHI','JKL','MNO','PQR','STU','VWX','YZ']
$groups=array_filter(array_combine($chunks,array_map(function($v)use($fruits){return array_values(preg_grep("/^[$v].*/i",$fruits));},$chunks)));
var_export($groups);
// $groups=array_filter( // remove keys with empty subarrays
// array_combine($chunks, // use $chunks as keys and subarrays as values
// array_map(function($v)use($fruits){ // check every chunk
// return array_values( // reset subarray's keys
// preg_grep("/^[$v].*/i",$fruits) // create subarray of matches
// );
// },$chunks)
// )
// );
すべてのコード出力と同じ結果:あなたはこれを行うことができ
array (
'ABC' =>
array (
0 => 'apple',
1 => 'Banana',
),
'DEF' =>
array (
0 => 'date',
),
'GHI' =>
array (
0 => 'guava',
),
'JKL' =>
array (
0 => 'kiwi',
1 => 'lemon',
),
'MNO' =>
array (
0 => 'Orange',
),
)
:
function buckets($array, callable $bucketFunc) {
$buckets = [];
foreach ($array as $val) {
$bucket = $bucketFunc($val);
if (!isset($buckets[$bucket])) {
$buckets[$bucket] = [];
}
$buckets[$bucket][] = $val;
}
return $buckets;
}
function myBucketFunc($value) {
//Gets the index of the first character and returns which triple of characters it belongs to
return floor((ord(ucfirst($value)) - ord("A"))/3);
}
$array = [ "Abc", "Cba", "Foo","Hi", "Bar" ];
$buckets = buckets($array, 'myBucketFunc');//Any function would
返します:
Array
(
[0] => Array
(
[0] => Abc
[1] => Cba
[2] => Bar
)
[1] => Array
(
[0] => Foo
)
[2] => Array
(
[0] => Hi
)
)
さらに明確化:
ord
は、文字のASCII値を返します。
Doing ord("X") - ord("A")
は、Xの文字インデックスを返します。
アルファベットを3文字ずつバケットに分割すると、その文字インデックスを3で割るとXのバケット番号が返されます。
私はインスピレーションを得た 'ord()'行が役立つことから、この回答をアップフォームしています。 – mickmackusa
これは、非スカラ方式でarray_reduce
の良い使用です:
function keyize(string $word, $stride = 3): string {
$first = strtoupper($word{0});
$index = (int)floor((ord($first) - ord('A'))/$stride);
return implode('', array_chunk(range('A', 'Z'), $stride)[$index]);
}
function bucketize(array $words, $stride = 3): array {
return array_reduce(
$words,
function ($index, $word) use ($stride) {
$index[keyize($word, $stride)][] = $word;
return $index;
},
[]
);
}
$words = [ 'alpha', 'Apple', 'Bravo', 'banana', 'charlie', 'Cucumber', 'echo', 'Egg', ];
shuffle($words);
$buckets = bucketize($words, 3); // change the number of characters you want grouped, eg 1, 13, 26
ksort($buckets);
var_dump($buckets);
だから私たちは歩いてarray_reduceを使用している - と同時に構築 - バケットを。バケット配列は各クロージャ呼び出しによってコピーされるため、実装するのが最も効率的です。しかし、コンパクトです。
あなたの単純な配列はどこですか?あなたの質問 –
でそれを更新してください。これはバケットに分割されている「ソート」ではありません。各バケットのサイズが1になるまで再帰的に実行し、バケットをマージすると、基数ソートが行われます。 – apokryfos
なぜこの並べ替えを使用するのが通常の並べ替えですか? – Zac