人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHP5.2.17で配列に関する質問です。
配列Aを配列Bに作り直したいのです。
配列イメージは補足に記入しました。

1. 配列Aの 'q_ansxx' の4つの部分だけ抜き出す。
(4つは、5つや6つになる可能性があり。'q_ans'の文字列に変更はない。)
2. 単純配列を2次元配列へ作り直し、q_ans01?04の数字の部分を新たに要素を作り代入。
(01?04の型は数字でなく文字列です。)
3. キーを維持したままシャッフル。

上記条件は結果が同じなら、順番が入れ替わっても問題ありません。
コードをご指南ください。
よろしくお願いしますm(_ _)m

●質問者: appfb
●カテゴリ:コンピュータ
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

質問者から

配列A

Array
(
[q_id] => 1
[q_que] => ほげほげ
[q_ans01] => あああ
[q_ans02] => いいい
[q_ans03] => ううう
[q_ans04] => おおお
[q_xxx] => 23
[q_date] => 2013-08-27 11:39:09
)

配列B

Array
(
[0] => Array
(
[q_key04] => 04
[q_ans04] => おおお
)
[1] => Array
(
[q_key02] => 02
[q_ans02] => いいい
)
[2] => Array
(
[q_key03] => 03
[q_ans03] => ううう
)
[3] => Array
(
[q_key01] => 01
[q_ans01] => あああ
)
)

1 ● a-kuma3
●50ポイント

クエリでやるっぽいですが、とりあえずコードを。

<?php
$foo = array(
 "q_id" => "1",
 "q_que" => "ほげほげ",
 "q_ans01" => "あああ",
 "q_ans02" => "いいい",
 "q_ans03" => "ううう",
 "q_ans04" => "おおお",
 "q_xxx" => "23",
 "q_date" => "2013-08-27 11:39:09"
 );

$bar = array();
foreach ($foo as $key => $value) {
 if (preg_match('/^q_ans(.+)/', $key, $match)) {
 array_push($bar, array($match[1], $value));
 }
}


shuffle($bar);

?>

ideone.com で試したのがこちら。
http://ideone.com/WpFk7W

変数のダンプを追加してます。




追記です。

ところで、補足の配列の例が紛らわしいですが、2次元のKEYの部分を'q_key'と'q_ans'に変えることはできますか?

確認不足で、すみません ><。
修正したのが、こちらです。

<?php
$foo = array(
 "q_id" => "1",
 "q_que" => "ほげほげ",
 "q_ans01" => "あああ",
 "q_ans02" => "いいい",
 "q_ans03" => "ううう",
 "q_ans04" => "おおお",
 "q_xxx" => "23",
 "q_date" => "2013-08-27 11:39:09"
 );
 
$bar = array();
foreach ($foo as $key => $value) {
 if (preg_match('/^q_ans(.+)/', $key, $match)) {
 $n = $match[1];
 array_push($bar, array('q_key' . $n => $n, 'q_ans' . $n => $value));
 }
}
 
 
shuffle($bar);
 
?>

ideone.com で試したのがこちら。
http://ideone.com/eoSV4S


appfbさんのコメント
ご回答ありがとうございます。 動作確認はとっくに出来ていたのですが、array_push() の挙動がいまいちわからなかったので確認していました。 やっと理解できました。 こんなに短くできるんですね。 ありがとうございます。 ところで、補足の配列の例が紛らわしいですが、2次元のKEYの部分を'q_key'と'q_ans'に変えることはできますか? 補足の配列例では'q_key01, q_key02 ・・・'となっていますが、'q_key'の間違いです。 ご回答いただいたコードで問題なく動作しますが、参考がてらお伺いできれば幸いです。

a-kuma3さんのコメント
>> ところで、補足の配列の例が紛らわしいですが、2次元のKEYの部分を'q_key'と'q_ans'に変えることはできますか? << 回答に追記しました。

appfbさんのコメント
バッチリでございます。 これで、array_pushも覚えました。 ありがとうございます。

2 ● Sampo
●50ポイント ベストアンサー

まず、q_ans01, q_ans02, q_ans03, q_ans04, … というカラムを用意している設計がよろしくありません。

http://www.slideshare.net/t_wada/sql-antipatterns-digest
こちらのスライドの41ページを開いてください。

個数可変の属性にカラムを一個ずつ作ろうというのは、「マルチカラムアトリビュート」という名前のついた悪手(「アンチパターン」)です。

ではどうするか。
選択肢テーブルを別に作るのです(さっきのスライドでは次のページに書いてある「従属テーブル」にあたります)。

テーブル名:Q_choice(pkey Q_id, choice_no)
Q_id(int), choice_no(int), text(varchar) 

Q_choiceからの取り出しは特に迷うことはありませんよね? 取り出してからshuffleしてもいいですし、ORDER BY RAND() をつけてシャッフルしつつ取り出してもかまいません。


さて、コメント欄で予告したUNIONの使い方。もしq_ans01, q_ans02, q_ans03, q_ans04が捨てられず、かつ、SELECT一発で取り出したければ

SELECT 1 AS No, q_ans01 AS Text
FROM Q_master WHERE Q_id={$id}
 UNION
SELECT 2 AS No, q_ans02 AS Text
FROM Q_master WHERE Q_id={$id}
 UNION
SELECT 3 AS No, q_ans03 AS Text
FROM Q_master WHERE Q_id={$id}
 UNION
SELECT 4 AS No, q_ans04 AS Text
FROM Q_master WHERE Q_id={$id}

と問い合わせれば
4行に延ばして取得ができます。

SELECT No, Text FROM
(
 SELECT 1 AS No, q_ans01 AS Text, RAND() AS rank
 FROM Q_master WHERE Q_id={$id}
 UNION
 SELECT 2 AS No, q_ans02 AS Text, RAND() AS rank
 FROM Q_master WHERE Q_id={$id}
 UNION
 SELECT 3 AS No, q_ans03 AS Text, RAND() AS rank
 FROM Q_master WHERE Q_id={$id}
 UNION
 SELECT 4 AS No, q_ans04 AS Text, RAND() AS rank
 FROM Q_master WHERE Q_id={$id}
) ORDER BY rank

とすればランダムシャッフルもできますね。


appfbさんのコメント
ご回答ありがとうございます。 なるほど・・・。 アンチパターンだという指摘はありがたいです。 まだ、複雑に絡む前ですので早速組みなおそうと思います。 ありがとうございます。 UNIONに関しては初めてなので、いただいた答えと照らし合わせいろいろ調べてみます。 ありがとうございました。

Sampoさんのコメント
ご紹介したスライドは「SQLアンチパターン」という本の紹介なのですが、この本はDBを扱うすべての人のマストリードです。 日本語版は今年出たばかりなのですが、これが5年前にあったらあんな苦労しないで済んだのに…という思い出がいろいろと。 ぜひ読んでみてください。 学生の方なら、図書館に購入リクエスト出すのもいいと思いますよ!

appfbさんのコメント
了解しました。 本まで紹介いただきありがとうございます。 経験者のアドバイスはとてもありがたいです。 早速、取り寄せてみます。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ