php-深くネストされた多次元配列の値を逆に計算します
会社の従業員の報酬を計算する必要があります。
私はこの構造を持っています(たとえば):
PHPでは、次の配列を表します:
<?php
$structure = [
"A" => [
"B" => [
"E" => [
"M" => null
],
"F" => [
"N" => [
"T" => null
],
"O" => null
],
"G" => [
"P" => null,
"Q" => [
"U" => null,
"V" => [
"X" => null,
"Y" => [
"3" => [
"4" => [
"4" => null,
"6" => null,
"7" => [
"8" => null
],
]
]
],
"Z" => null
]
]
],
"H" => null
],
"C" => [
"I" => null,
"J" => [
"R" => null
],
"K" => [
"S" => [
"W" => [
"1" => null,
"2" => null,
]
]
]
],
"D" => [
"L" => null
]
]
];
各従業員の報酬を計算する必要があります。最終部下は自分の仕事からのみ報酬を得る。しかし、他の部下がいる先輩は、自分の仕事から報酬を得て、部下を働かせます。
例:
人Aには独自の報酬10があります。 Dの人は自分の報酬20を持っています。 Lの人には独自の報酬15があります。
決勝では、 L の人は最終報酬15(最終)を持っています。 D の人には、最終的な報酬が20 + 15 = 35(D + L)あります。 Aの人には最終的な報酬が10+35(A + D)あります。
計算は以下で実行する必要がありますが、ネットワークは任意に深くすることができます。計算私はいくつかの部分に分割したいと思います。 (パフォーマンス上の理由から)
- 構造を適切な形式に修正するスパイダー。
- 各ノードの報酬を計算します。
- 各ノードに関する情報をメールで送信します。
構造全体を進める方法がわかりません。または、構造を再編成して簡単に実行できるようにします。何か考えられますか?
ありがとうございます。ありがとう! @マーティン
//編集:生のデータベース
| id | parent | name
//編集:新しいデータ構造:
{-code-3}
答え :
答え :
解決策:
これは、構造を裏返しから再帰的にトラバースすることで実行でき、見つけた各従業員の報酬をフラット化された2D配列に格納します。
ツリーのバックアップを計算するには基本値が必要なため、開始値を持つ構造の各リーフに依存します。
RecursiveIteratorIteratorをCHILD_FIRSTフラグとともに使用すると、配列'backwards'をループできます。これは、この場合、開始報酬がある場所であるため、この場合に必要です。ツリーをたどると、部下の報酬を取得し、それを現在の従業員に追加して続行します。したがって、構造の先頭に戻るまでに、すべての従業員を計算しました。
結果をフラット化された配列に格納すると、ロジックに沿ってさらに使いやすく、操作しやすくなります。
想定される開始構造:
// Each leaf has a value (random for example sake)
$structure = [
"A" => [
"B" => [
"E" => [
"M" => 10
],
"F" => [
"N" => [
"T" => 15
],
"O" => 5
],
"G" => [
"P" => 40,
"Q" => [
"U" => 30,
"V" => [
"X" => 35,
"Y" => [
"3" => [
"4" => [
"5" => 5,
"6" => 10,
"7" => [
"8" => 20
],
]
]
],
"Z" => 30
]
]
],
"H" => 15
],
"C" => [
"I" => 25,
"J" => [
"R" => 25
],
"K" => [
"S" => [
"W" => [
"1" => 40,
"2" => 50,
]
]
]
],
"D" => [
"L" => 15
]
]
];
計算:
// Iterate through the structure from the outside-in (child/leaves first)
$data = new RecursiveArrayIterator($structure);
$dataIt = new RecursiveIteratorIterator($data, RecursiveIteratorIterator::CHILD_FIRST);
$rewards = [];
foreach ($dataIt as $value) {
$subKeys = [];
$rewards[$dataIt->key()] ?? $rewards[$dataIt->key()] = 0; // Suppress any undefined index errors
if (is_array($value)) {
$subKeys = array_keys($value);
// traverse through all branches to obtain the existing reward values for subordinates
array_walk_recursive($value, function($reward, $person) use (&$subKeys) {
$subKeys[] = $person;
});
$subKeys = array_unique($subKeys);
foreach ($subKeys as $employee) {
$rewards[$dataIt->key()] += $rewards[$employee];
}
} else {
$rewards[$dataIt->key()] += $value;
}
}
print_r($rewards);
リターン/最終配列:
Array
(
[M] => 10
[E] => 10
[T] => 15
[N] => 15
[O] => 5
[F] => 35
[P] => 40
[U] => 30
[X] => 35
[4] => 60
[6] => 10
[8] => 20
[7] => 20
[3] => 90
[Y] => 180
[Z] => 30
[V] => 335
[Q] => 520
[G] => 745
[H] => 15
[B] => 1060
[I] => 25
[R] => 25
[J] => 25
[1] => 40
[2] => 50
[W] => 90
[S] => 180
[K] => 270
[C] => 435
[L] => 15
[D] => 15
[A] => 1935
)
各ノードの従業員数を取得するには、 count
を使用して1行で簡単に取得できます:
$ employeesPersonA = count($ structure ['A']、COUNT_RECURSIVE); // 33
$ employeesPersonC = count($ structure ['A'] ['C']、COUNT_RECURSIVE); // 8
$ employeesPersonK = count($ structure ['A'] ['C'] ['K']、COUNT_RECURSIVE); // 4
編集: データベース構造の場合、データベースから多次元の結果セットを取得することはできないため、結果セットを調べて、そこからPHPで構造を構築するしかありません。
答え :
解決策:
ノード「A」、「B」、「C」、「D」、および「L」のみを考慮するように簡略化した1つの例を次に示します...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(user CHAR(1) NOT NULL PRIMARY KEY
,lft INT NOT NULL
,rgt INT NOT NULL
);
INSERT INTO my_table VALUES
('A',1,10),
('B',2,3),
('C',4,5),
('D',6,9),
('L',7,8);
SELECT y.user
, GROUP_CONCAT(x.user ORDER BY x.lft) nodes
FROM my_table x
JOIN my_table y
ON x.lft BETWEEN y.lft AND y.rgt
GROUP
BY y.user
ORDER
BY y.lft;
+------+
同様の質問
私たちのウェブサイトで同様の質問で答えを見つけてください。