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

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

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

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

Q&A

3回答

1025閲覧

PHP 多次元配列の条件付マルチソートについて

d__..___

総合スコア18

PHP

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

0グッド

1クリップ

投稿2020/03/03 21:49

編集2020/03/05 00:51

添え字、果物、個数
1 apple 10
2 orange 5
3 orange 2
4 melon 6
5 banana 3
6 apple 4

このよう多次元配列において、同じ果物がある場合は、
質問1)個数の大きいもののみ残してソートする、その際添え字は振り直す
質問2)個数の大きいもののみ残して、果物のアルファベット順にソートする (添え字は再度振りなおす)をしたいです。

質問1の理想的な実行結果)

1 apple 10
2 orange 5
3 melon 6
4 banana 3

質問2の理想的な実行結果)

1 apple 10
2 banana 3
3 melon 6
4 orange 5

このようにしたいのですが、PHPのarray_uniqueには多次元配列は対応していません。

array_keys()を使って個数を取得し、maxを使ってなんとかならないか・・
array_multisort をうまく使えないか・・・
とアルゴリズムを考えています。
アドバイスお願いします。

PHP

1$item = <<< FORM 21 apple 10 32 banana 3 43 melon 6 54 orange 5 6FORM; 7 8$item = explode("\n",$item); 9$item2 = array(); 10foreach($item as $value){ 11$item2[] = explode(" ",$value); 12} 13 14/* 15これで多次元配列$item2 に配列としてデーターが入る 16 17 18*/

#追記

こんなかんじのアルゴリズムを思いついたのですが、
//もしみつかったら既存の配列と比較して、大きいほうのみ残す
この処理を使って書く方法はありませんか?
ループではapple,10が先に格納されていて、あとのapple,4と比較したとき
10 > 4
なので、apple4は格納しない
というイメージです。
orangeの場合は、先にorange,2が格納されているので
orange,5と比較すると5のほうが大きいので、orange,2を削除してorange,5を格納する
ということです。

処理としては
}else{
//もしみつかったら既存の配列と比較して、大きいほうのみ残す

}

この部分に記載したいです。この部分に記載するアルゴリズムを教えてください。

PHP

1<? 2$org = [ 3 ['apple', 10], 4 ['orange', 2], 5 ['orange', 5], 6 ['melon', 6], 7 ['banana', 3], 8 ['apple', 4], 9]; 10 11 $tmp = array(); 12 $array_result = array(); 13 14 foreach( $org as $key => $value ){ 15 16 // 配列に値が見つからなければ$tmpに格納 17 if( !in_array( $value[0], $tmp ) ) { 18 $tmp[] = $value[0]; 19 $array_result[] = $value; 20 }else{ 21//もしみつかったら既存の配列と比較して、大きいほうのみ残す 22 23 } 24 25 } 26 $data = $array_result; 27 28print_r($data); 29?>

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

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

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

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

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

m.ts10806

2020/03/03 22:11

コードはマークダウンのcode機能を利用してご提示ください。
d__..___

2020/03/03 22:18

修正しました
m.ts10806

2020/03/05 00:41

あとから追加されたコードもマークダウン対応願います
guest

回答3

0

php

1<?php 2 3class Item 4{ 5 private $name; 6 private $count; 7 8 function __construct($array) 9 { 10 $this->name = $array[0]; 11 $this->count = $array[1]; 12 } 13 14 function toArray() 15 { 16 return [$this->getName(), $this->getCount()]; 17 } 18 19 function getName() 20 { 21 return $this->name; 22 } 23 24 function getCount() 25 { 26 return $this->count; 27 } 28} 29 30class ItemCollection 31{ 32 private $assoc; 33 34 function __construct($array) 35 { 36 foreach ($array as $item) { 37 if (isset($this->assoc[$item[0]])) { 38 if ($this->assoc[$item[0]]->getCount() >= $item[0]) continue; 39 } 40 $this->assoc[$item[0]] = new Item($item); 41 } 42 } 43 44 function sortByCounts() 45 { 46 uasort($this->assoc, "itemSortByCountsDesc"); 47 } 48 49 function sortByNames() 50 { 51 uasort($this->assoc, "itemSortByNamesAsc"); 52 } 53 54 function toArray() 55 { 56 $ret = []; 57 foreach ($this->assoc as $item) { 58 $ret[] = $item->toArray(); 59 } 60 return $ret; 61 } 62} 63 64function itemSortByCountsDesc($a, $b) 65{ 66 return $b->getCount() > $a->getCount(); 67} 68 69function itemSortByNamesAsc($a, $b) 70{ 71 return $a->getName() > $b->getName(); 72} 73 74$org = [ 75 ['apple', 10], 76 ['orange', 5], 77 ['orange', 2], 78 ['melon', 6], 79 ['banana', 3], 80 ['apple', 4], 81]; 82$collection = new ItemCollection($org); 83$collection->sortByCounts(); 84var_export($collection->toArray()); 85$collection->sortByNames(); 86var_export($collection->toArray());

結局無名関数がどうこう以前にやってることが複雑なんで、そういうことを単純にやるために class があると思います。

投稿2020/03/04 16:35

papinianus

総合スコア12705

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

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

d__..___

2020/03/05 00:10

アイデアありがとうございます
d__..___

2020/03/05 05:22

質問なのですが function __construct($array) { foreach ($array as $item) { このループで print_r($this->assoc); これを実行したら Array ( [apple] => Item Object ( [name:Item:private] => apple [count:Item:private] => 10 ) ) Array ( [apple] => Item Object ( [name:Item:private] => apple [count:Item:private] => 10 ) [orange] => Item Object ( [name:Item:private] => orange [count:Item:private] => 5 ) ) if 5 でかい orangeArray ( [apple] => Item Object ( [name:Item:private] => apple [count:Item:private] => 10 ) [orange] => Item Object ( [name:Item:private] => orange [count:Item:private] => 2 ) ) Array ( [apple] => Item Object ( [name:Item:private] => apple [count:Item:private] => 10 ) [orange] => Item Object ( [name:Item:private] => orange [count:Item:private] => 2 ) [melon] => Item Object ( [name:Item:private] => melon [count:Item:private] => 6 ) ) Array ( [apple] => Item Object ( [name:Item:private] => apple [count:Item:private] => 10 ) [orange] => Item Object ( [name:Item:private] => orange [count:Item:private] => 2 ) [melon] => Item Object ( [name:Item:private] => melon [count:Item:private] => 6 ) [banana] => Item Object ( [name:Item:private] => banana [count:Item:private] => 3 ) ) こうなっていました。 重複のorangeの5が2に置き換わってるのですが、どこでその処理がおきているのでしょうか?
papinianus

2020/03/05 14:06

動作確認をしたので5が2にはならないようにした気がします。(確認しましたが、やはり5のままでした) > このループで > print_r($this->assoc); > これを実行したら そのループは 複数行あるので、どこで実行したかによると思います。またそれを足しても↓のような表示は出ないので、他にも何かをしたのではないかと想像されます。 私が内容を知らないコードについて、どこでその処理が起きているかは答えられないです。 > if 5 でかい orangeArray おそらくですが、 > if ($this->assoc[$item[0]]->getCount() >= $item[0]) continue; この if をかきかえてしまったのだと思います。コードはバージョン管理していると思うのでコミット履歴を見てください。
guest

0

考え方としては、以下で良いかと

・数字はどうせ振り直すので一旦捨てる
・入力を、key を果物、value を個数としてさばく
・その際、key が重なるのであれば、value を比較し、でかい方を選択
・最後に、key をアルファベットでソート
・ソートした配列を元に、数字を振り直した配列を作成

最後の「振り直した配列」は表示の際にただ行番号を入れたいだけなら、新たに作らなくても、「表示の際に連番ふる」だけで良いと思います。

質問の元が競技っぽい気がしたのでコードは書きませんが、参考まで。

投稿2020/03/03 22:10

編集2020/03/03 22:12
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2020/03/03 22:31

foreach で回す必要がありますが、私の記述した処理はそれぞれ各1行で済みます。 関数化されても、逆に仕様を理解し、覚えるほうが面倒です。 *まぁ、php の配列に関する関数は多いので、適当なものが使えるかもしれませんが、仕様を理解するのはかなり大変です。
guest

0

こんなかんじでやってください

投稿2020/03/04 00:41

yambejp

総合スコア114747

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

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

yambejp

2020/03/04 00:43 編集

$org=[ ['apple' ,10], ['orange', 5], ['orange', 2], ['melon' , 6], ['banana', 3], ['apple' , 4], ]; $new=array_map(function($x) use($org){ $d=max(array_map(function($y){ return $y[1]; },array_filter($org,function($y) use($x){ return $y[0]==$x; }))); return [$x,$d]; },array_unique(array_map(function($x){ return $x[0]; },$org))); usort($new,function($x,$y){ return $x>$y; }); print_r($new);
d__..___

2020/03/04 04:14

ありがとうございます。 初歩的な質問で申し訳ないのですが array_map(function($y){ このような書き方をはじめてみました。 なぜ「;」で終わらせるのではなく「{」で開いているのでしょうか その書き方は従来の書き方だとどのような方法で記載できますか?
yambejp

2020/03/04 04:16 編集

> なぜ「;」で終わらせるのではなく「{」で開いているのでしょうか ちょっと質問の意図がわかりませんが、一度マニュアルを確認されるとよいでしょう https://www.php.net/manual/ja/function.array-map.php
d__..___

2020/03/04 04:24

調べていたのですが、その書き方はクロージャ?という書き方をしているのでしょうか? https://www.php.net/manual/ja/functions.anonymous.php 通常は array_map('cube', $a); ↑ このような書き方をすると思います。 array_map(function($x) use($org){ このような書き方は見たことがありません。
yambejp

2020/03/04 04:27

> このような書き方 なるほど、そこの話ですね いわゆるコールバック関数に無名関数を指定しているということです コールバック関数はarray_mapが実行する実態になる部分 無名関数はfunction(){}という書き方をすると命名しないでもその場限りで指定ができる仕組みです
d__..___

2020/03/04 04:28

はい!その話です。ありがとうございます。 これを無名関数を使わないように書いたらどのようになるのでしょうか? 無名関数を使ったことがなくて、いまいち処理が理解できません・・
d__..___

2020/03/04 15:24

質問の趣旨がずれるので、新しく無名関数について質問しなおします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問