質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

1885閲覧

PHPで条件に適合する配列を連結したい

love_kinniky

総合スコア22

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2019/02/01 18:45

編集2019/02/02 09:27

###実現したいこと
PHP初心者で、配列の合体がどうしてもできません。

下記の「現在の配列$current」と「新しい配列$new」を合体して、「目的の配列$update」にしたいと考えています。

###そのための条件
合体の条件は3つありまして、

thread_idが同じなら次の➁➂で合体する。違えば「新しい配列$new_array」を先頭にして普通に連結する。

合体させるときは、
timesender_idreadの3つについて、新しい配列の値だけを使う。
➂新しい配列を先頭に持っていく。

です。

これを実現するために文末のソースコードを書いて奮闘しているのですが、どうしてもできず、質問させて頂きました。

###「現在の配列($current_array)」と「新しい配列($current_array)」
まずこの2つの配列のうちthread_idが同じものを合体させたいです。

php

1<?php 2/* 3* 現在の配列($current_array) 4* いくつあるか不明(例として次の2つ) 5*/ 6$current_array = array( 7 array( 8 'action'=>'message', 9 'time'=>'16', 10 'sender_id'=>'9', 11 'recipient_id'=>'1', 12 'read'=>'ok', 13 'thread_id'=>'8' 14 ), 15 array( 16 'action'=>'message', 17 'time'=>'13', 18 'sender_id'=>'4', 19 'recipient_id'=>'1', 20 'read'=>'ok', 21 'thread_id'=>'5' 22 ), 23); 24 25/* 26* 新しい配列($new_array) 27* 1つだけ 28*/ 29$new_array = array( 30 array( 31 'action'=>'message', 32 'time'=>'18', 33 'sender_id'=>'9', 34 'recipient_id'=>'1', 35 'read'=>'yet', 36 'thread_id'=>'5' 37 ), 38);

###「目的の配列($current)」
上の2つの合体で作りたいのが下記になります。

php

1<?php 2/* 3* 目的の配列($update_array) 4*/ 5$current_array = array( 6 array( // thread_idが同じなので合体した 7 'action'=>'message', 8 'time'=>'18', 9 'sender_id'=>'9', 10 'recipient_id'=>'1', 11 'read'=>'yet', 12 'thread_id'=>'5' 13 ), 14 array( // thread_idが違うので変化なし 15 'action'=>'message', 16 'time'=>'16', 17 'sender_id'=>'9', 18 'recipient_id'=>'1', 19 'read'=>'ok', 20 'thread_id'=>'8' 21 ), 22); 23

###考えているソースコード
あくまでイメージですが、このような流れになるのではと書いてみました。
素人の付け焼刃ゆえ、お目汚しかとは思いますが…

php

1<?php 2/* 3* $current_arrayと$new_arrayの合体の関数 4* usage: $update_array = mymerge($new_array, $current_array); 5*/ 6function mymerge($arg1, $arg2) { 7 foreach ($arg1 as $new => $newVal) { 8 foreach ($arg2 as $current => $currentVal) { 9 // thread_id が同じ場合は、新しい配列の値を採用して、新しい配列を先頭に持っていく 10 if ( $new[5]['thread_id'] == $current[5]['thread_id'] ) { 11 $currentVal['time'] = $newVal['time']; 12 $currentVal['sender_id'] = $newVal['sender_id']; 13 $currentVal['read'] = $newVal['read']; 14 return $arg2; 15 } 16 // thread_id が異なる場合は現在の配列と新しい配列を結合して、新しい配列を先頭に持っていく 17 else{ 18 $arg1_arg2 = array_merge($arg1, $arg2); 19 return $arg1_arg2; 20 } 21 } 22 } 23} 24 25 26/* 27* 上の関数を使って、目的の配列 ($update_array)を作る 28*/ 29$update_array = mymerge( $new_array, $current_array ); 30var_export($update_array); 31?>

どのようにすればmymergeは「目的の配列($update_array)」を作れるような関数にできがるでしょうか。
質問で分かりにくい点などございましたらご指摘ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/02 02:21

せっかくコードを作られたのでしたら実行されてみては?デバッグも行えば見えてくるものもあると思います。何のために置かれたかわからないbreakとか
love_kinniky

2019/02/02 09:12

ありがとうございます。breakはforeachの最後に必ず必要なものだと思っていますが、そのようなことなはないのでしょうか?
m.ts10806

2019/02/02 09:16

ないです。foreachは配列を全てループするので勝手に抜けます。 意図的にループを抜けたいときにbreakを使うことはありますが、それならwhileでループ抜ける条件をつけるべきで、switch以外でbreakを使う機会はあまりありません。
love_kinniky

2019/02/02 09:53 編集

そうでしたか…breakを消して、いくつか手直してしてみました。ありがとうございます。
guest

回答2

0

前回の回答がお目汚しと認知されてしまったようですので。

前提とすること

  • $new_arrayは1つしかない
  • $new_array['thread_id']とマッチするthread_idは$current_arrayにはたかだか1つしかない
  • 順序性を重んじる

前回のように、先頭に追加してそのうち20個だけを取る、それも一部要素だけ、とかっていうphp的にトリッキーな制約がなければループしなくてもarray_mergeでできるんで、そこまで酷いコードにはなりません。

php

1<?php 2/* 3* 現在の配列($current_array) 4* いくつあるか不明(例として次の2つ) 5*/ 6$current_array = array( 7 array( 8 'action'=>'message', 9 'time'=>'16', 10 'sender_id'=>'9', 11 'recipient_id'=>'1', 12 'read'=>'ok', 13 'thread_id'=>'8' 14 ), 15 array( 16 'action'=>'message', 17 'time'=>'13', 18 'sender_id'=>'4', 19 'recipient_id'=>'1', 20 'read'=>'ok', 21 'thread_id'=>'5' 22 ), 23); 24 25/* 26* 新しい配列($new_array) 27* 1つだけ 28*/ 29$new_array = array( 30 array( 31 'action'=>'message1', //この値を利用していないことの確認のため1を付与 32 'time'=>'18', 33 'sender_id'=>'9', 34 'recipient_id'=>'11', //この値を利用していないことの確認のため1を付与 35 'read'=>'yet', 36 'thread_id'=>'5' 37 ), 38); 39 40$res = insertMerge($new_array, $current_array); 41var_dump($res); 42 43function insertMerge($ins, $data) { 44 $ins = array_pop($ins); 45 $needle = $ins['thread_id']; 46 $thread_ids = array_column($data, 'thread_id'); 47 if($idx = array_search($needle, $thread_ids,true) === false) { return $data; } //thread_idがなかったら元のままにする 48 unset($ins['recipient_id']); 49 unset($ins['action']); 50 $ins = array_merge($data[$idx], $ins); 51 unset($data[$idx]); 52 return array_merge([$ins], $data); 53}

投稿2019/02/04 02:15

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

love_kinniky

2019/02/05 13:21

こんばんは。遅くなってしまい申し訳ございません。ループでなくてもいいんですね。thread_idと一致するかどうか検知するのにループ必須かと思っていたので、array_columnなど大変勉強になりました。ありがとうございます。
guest

0

ベストアンサー

条件を簡潔にすると良いです。

$new_arrayからthread_idだけを取り出し、$current_array[n]['thread_id']と比較すると楽です。

補足
関数の使い方が理解できていないようです。
提示されたコードで言うと
・関数の引数の関数内での使用方法
・$item のスコープ
・return の使用箇所
がおかしいです。

追記
そのままじゃ使えないけどサンプルコードw

php

1$result_array = $new_array; 2$target_thread_id = $new_array[0]['thread_id']; 3 4foreach($current_arrays as $current_array){ 5 if($current_array['thread_id'] === $target_thread_id){ 6 $result_array[0] = array( 7 'action'=>$current_array['action'], 8 'time'=>$new_array[0]['time'], 9 'sender_id'=>$new_array[0]['sender_id'], 10 'recipient_id'=>$current_array['recipient_id'], 11 'read'=>$new_array[0]['read'], 12 'thread_id'=>$current_array['thread_id'] 13 ); 14 } else { 15 $result_array[] = $current_array; 16 } 17} 18var_dump($result_array);

概要:
$result_array という結果を入れる配列を作り、$new_array を突っ込んでおきます。
つまり $result_array[0]。これが結構コードをシンプルにしてます。
で、$current_arrays をぐるぐるまわし、thread_id が合致した場合、$result_array[0] を置き換え、合致しなければ、$result_array の後ろへ。

注意:
提示されたコードの $current_array は $current_arrays として使用しています。

投稿2019/02/02 00:52

編集2019/02/02 09:42
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

love_kinniky

2019/02/02 09:03

その楽な方法が難しいですw 自分としては foreach ($arg1 as $item) { で新しい配列を1件ずつ処理して foreach ($arg2 as $key=>$val) { で現在の配列を1件ずつ処理して そして if ( $item['thread_id'] == $val['thread_id'] ) { でそれら1件ずつの中の「thread_id」が一致したら、 というまさに仰る条件にしているつもりでして…
退会済みユーザー

退会済みユーザー

2019/02/02 09:45

概要をコードにしてみました。 $new_array が1件しかないのであれば、foreach を使用する必要ないです。 先頭に持ってくる件は、最初から先頭においておけば良い。 プログラミングでは時々順番を入れ替えてコードをシンプルにすることがあります。 どの錠処理が「絶対に順番を守らなければならないのか?」を考えるのも面白いですよ。
love_kinniky

2019/02/02 09:47

回答のご修正、どうもありがとうございます。もうやめるしかないと思っていたのでとてもうれしいです。 どちらかを操作して出力するのではなくて、出力用のresult_arrayという配列を作ってその値を順にコピーしていくという方法ですか!すごいや!ありがとうございます。 でもどうして $current_arrays にされたのでしょうか? $current_array にすればそのまま使えますよね?
退会済みユーザー

退会済みユーザー

2019/02/02 09:52 編集

foreach で回すのは複数のものなので、たいてい複数形で命名します。 で、foreach の中では単数形で使うってのが、ワリとわかりやすい記述なので変更してます。 つまり、コード見た時にわかりやすくなるルールにしたかったんで変えました。
love_kinniky

2019/02/02 10:05

今自分でアレンジしていたらできなくなって、まさにそこが原因でしたw名前、大事ですね。どうもありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問