• ベストアンサー

配列の要素を任意の数で割って、割り振る方法

$abc = array("A", "B", "C", "D", "E", "F", "G", "H", "I"); 上記のような配列があったとします。 これを任意の数で割って、割り振っていきたいのですが、例えば7で割ったとしたら、 1. A, B 2. C, D 3. E 4. F 5. G 6. H 7. I という風に、割り振りたいのですが、どのようにすれば、こういったことがPHPのプログラムで実現できるか教えてください。 もしくは、 1. A, H 2. B, I 3. C 4. D 5. E 6. F 7. G という割り振り方でも大丈夫です。

質問者が選んだベストアンサー

  • ベストアンサー
noname#244856
noname#244856
回答No.3

【foreach ($abc as $i => $v) $new[$i % $max][] = $v;】 $i % $max は剰余を計算するので、$maxが7であるとすると、以下のような順序でループします。 0 % 7 → 0 1 % 7 → 1 2 % 7 → 2 3 % 7 → 3 4 % 7 → 4 5 % 7 → 5 6 % 7 → 6 0 % 7 → 0 1 % 7 → 1 2 % 7 → 2 ... 「もしくは、...という割り振り方でも大丈夫です」ということでしたので、実装しやすいこちらを選びました。 -------------------------------------------- 【$new = array_map(function ($vl) { return implode(', ', $vl); }, $new);】 こちらは2次元配列の中に作成された1次元配列を、「, 」で結合しているだけです。 array(  array('A', 'H'),  array('B', 'I'),  array('C'),  array('D'),  array('E'),  array('F'),  array('G'), ) これが array(  'A, H',  'B, I',  'C',  'D',  'E',  'F',  'G', ) こうなります。 function ($vl) { return implode(', ', $vl); } という無名関数を内側の各配列に対して適用し、returnされてきた文字列を新しい配列にセットしていく感じです。キーはそのまま使用されます。まあ分かりにくかったら [A] $new = array(); $max = count($abc); foreach ($abc as $i => $v) $new[$i % $max][] = $v; foreach ($new as &$v) $v = implode(', ', $v); unset($v); もしくは [B] $new = array(); $max = count($abc); foreach ($abc as $i => $v) $new[$i % $max][] = $v; foreach ($new as $i => $v) $new[$i] = implode(', ', $v); と書くのもナシでは無いです。ただ [A]…「外側でunsetしないと次に$vという変数に代入したときに$newが破壊される」 [B]…「PHPのforeachの実装を理解していないと、現在回している配列自体を書き換えたときの挙動が理解しにくい」 という欠点があります。 -------------------------------------------- 【その他】 まずはマニュアルで気になった関数の使い方を読んでみてください。 [配列関数] http://php.net/manual/ja/ref.array.php メリットがよく分からなければ、以下の記事を読んでみるといいと思います。 [PHPでできる関数型プログラミング] http://my-rest.icca.jp/blog/2011/01/477/ http://my-rest.icca.jp/blog/2011/01/506/ http://my-rest.icca.jp/blog/2011/02/524/ PHPは関数型言語寄りの記述があまり得意ではないので、狂ったみたいにこの書き方に拘る必要はもちろん無いと思います。あくまで「ここは関数型っぽく書いた方がきれいに書ける!」と感じたら採用すればいい程度です。 以下はカレンダーの2次元配列を作成する例ですが、圧倒的に関数型の方がきれいに書ける一例です。 [最もシンプルなカレンダー生成ロジック] http://qiita.com/mpyw/items/0a475bc4891a3a2940e8 ちなみに今回の問題をRubyで解決するならば以下のように書けますね。Rubyはあんまり詳しくないのでもっといい書き方とかあるかもしれませんが、これだけでも十分綺麗に書けてるとは思います。 abc = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] new = abc  .each_with_index  .group_by{|v, k| k % 7}  .values  .map{|v| v.map(&:first)}

h_mp
質問者

お礼

任意の数字で割るには、$maxの数値を書き換えればいいわけですね。 余りが0から増えていったり、一度2次元配列にして、,でつないで1次元の配列に戻すみたいなやり方は全く発想になかったので、とても勉強になります。 リンクもありがとうございます。 マニュアルや、関数型プログラミングのページ読んでみます。 大変詳しくありがとうございました。

すると、全ての回答が全文表示されます。

その他の回答 (3)

noname#244856
noname#244856
回答No.4

訂正 0 % 7 → 0 1 % 7 → 1 2 % 7 → 2 3 % 7 → 3 4 % 7 → 4 5 % 7 → 5 6 % 7 → 6 0 % 7 → 0 1 % 7 → 1 2 % 7 → 2 ↓ 0 % 7 → 0 1 % 7 → 1 2 % 7 → 2 3 % 7 → 3 4 % 7 → 4 5 % 7 → 5 6 % 7 → 6 7 % 7 → 0 8 % 7 → 1 9 % 7 → 2

h_mp
質問者

お礼

修正ありがとうございます。

すると、全ての回答が全文表示されます。
noname#244856
noname#244856
回答No.2

$new = array(); $max = count($abc); foreach ($abc as $i => $v) $new[$i % $max][] = $v; $new = array_map(function ($vl) { return implode(', ', $vl); }, $new);

h_mp
質問者

お礼

回答ありがとうございます。 申しわけないのですが、それぞれどういう意図なのか説明していただけると幸いです。

すると、全ての回答が全文表示されます。
noname#246457
noname#246457
回答No.1

参考までに テスト(自分のサーバー):http://pro.mnas.0am.jp/TMP/q8833138.php <?php $cnt =7;//任意の数 $abc = array("A", "B", "C", "D", "E", "F", "G", "H", "I"); for($i = 0,$i2 = 0,$i3 = 0 ;$i3 < count($abc);$i ++ , $i3 ++ ){ //配列の場合0からです。 if( $cnt == $i ){ $i = 0; $i2 ++; } $kekka[$i][$i2] = $abc[$i3]; } //結果表示 for($i=0,$i1=0;$i1<count($kekka);$i1++){ echo "".$i1."."; for($i = 0 ; $i < count($kekka[$i1]) ; $i++){ echo $kekka[$i1][$i]; echo ","; } echo "<br />"; } //二個目がないのにかかわらず「,」がつくのは手抜きです。$flagなんて追記したらすぐ修正できます。 exit(); ?>

参考URL:
http://pro.mnas.0am.jp/TMP/q8833138.php
h_mp
質問者

お礼

サーバーにまで上げていただいて、ありがとうございます。 とてもわかりやすいロジックだと思いました。 ありがとうございました。

すると、全ての回答が全文表示されます。

専門家に質問してみよう