如何有条件地合并多维数组


How to conditionally merge a multi-dimensional array

我有一个多维数组:

Array
(    
    [10] => Array
    (
        [from] => Jack
        [to] => Terry
        [Bribe] => 0
        [Joke_Payment] => 0
        [Corrupt_Support] => 1
        [Legitimate_Support] => 0
        [Obfuscation] => 1
        [Legal_Enforcement] => 0
        [Whistleblower] => 0
    )
    [11] => Array
    (
        [from] => Terry
        [to] => Jack
        [Bribe] => 0
        [Joke_Payment] => 0
        [Corrupt_Support] => 1
        [Legitimate_Support] => 0
        [Obfuscation] => 0
        [Legal_Enforcement] => 1
        [Whistleblower] => 0
    )
)

我想更新上面的数组如下:有一个1(从tofrom)和一个-1表示相反的方向,一个2表示"两个方向"。

 Array (    [10] => Array
         (
             [from] => Jack
             [to] => Terry
             [Bribe] => 0
             [Joke_Payment] => 0
             [Corrupt_Support] => 2
             [Legitimate_Support] => 0
             [Obfuscation] => 1
             [Legal_Enforcement] => -1
             [Whistleblower] => 0
         ) }

如何首先计算它们的交集,然后更新原始数组?

它们的键数量相同,当fromto匹配,tofrom元素匹配时,我想将这两个数组合并为一个。"1"用于表示该属性在fromto方向上相关,而-1表示该属性的方向相反(从tofrom)。

我当前的代码是:

$fileRelation = explode("'r", $end);
$rowsRelation = array_map('str_getcsv', $fileRelation);
$headerRelation = array_shift($rowsRelation);
$csvArrRelation = array();
$countR = count($headerRelation);
foreach ($rowsRelation as $key => &$row) {
    $index = 2;$sum = 0;$sumArr = array();
    while ($index < $countR) {
        if ($row[$index]>0) {
            $sumArr[$sum]=$index; //store row $headerRelation index
            $sum++;
        }
        $index++;
    }
    if($sum > 0){ //remove element if no relationship exist
        foreach ($csvArrRelation as $k => $a) {
            if (in_array($row[0], $csvArrRelation[$k]) && in_array($row[1], $csvArrRelation[$k])){
                $p = array_values($a);$i = 2;$cp= count($p);
                while($i < $cp ){
                if($row[$i] == $p[$i]){
                    $a[$headerRelation[$i]] += $row[$i];
                }else{
                    $a[$headerRelation[$i]] -= $row[$i];
                }
                $i++;
            }
                unset( $rowsRelation[$key] );
            }
        }
        $csvArrRelation[] = array_combine($headerRelation, $row);
    }
}

我不会为您写这篇文章,但这里有一个好的开始:

$newRelations = [];
$deletions = [];
foreach ($rowsRelation as $key1 => $row1)
{
    foreach ($rowsRelation as $key2 => $row2)
    {
        // Don't compare with self
        if ($key1 != $key2)
        {
            // Have we found a reverse match?
            if (
                $row1['from'] == $row2['to'] &&
                $row1['to'] == $row2['from']
            )
            {
                $newRelations[] = myMerge($row1, $row2);
                $deletions[] = $key1;
                $deletions[] = $key2;
            }
        }
    }
}
// Delete old rows
foreach ($deletions as $deleteKey)
{
    unset($rowsRelation[$deleteKey]);
}
//  Add in new rows
$rowsRelation = array_merge($rowsRelation, $newRelations);
function myMerge(array $row1, array $row2)
{
    // todo
}

我的策略是将每一行相互比较,如果发现反向匹配,我们就知道应该合并。为了避免损坏foreach循环,我将新的数组值添加到不同的数组中,并记录我希望从原始数组中删除哪些键。然后在工作完成后将这些内容合并/删除。

我认为这是某种游戏,所以让我们称"玩家1"为名称出现在"from"字段中的玩家,称"玩家2"为名称显示在"to"字段中。

根据我的理解,你认为球员1的价值观是积极的,而球员2的价值观则是消极的。然后将"从玩家1到玩家2"记录中的两个值相加,并丢弃"从玩家2到玩家1"记录。

根据该规则,Corrupt_Support最终的值应该是0,而不是2。
基本上,在合并记录后,您将无法区分完全没有操作和相互取消的操作。

此外,没有选择"获胜者"的规则,即哪个"来自"的球员将被保留,这可能会导致不切实际的结果
如果你有3名玩家Abe、Bob和Cal,你可以得到任何可能的订单,例如
["Abe vs Bob", "Bob vs Cal" and "Cal vs Abe"]
["Abe vs Bob", "Abe vs Cal" and "Cal vs Bob"]
在后一种情况下,查找Bob的操作将是相当有问题的。

现在,如果你仍然想这样做,这里有一种方法可以利用PHP哈希表来加快合并速度,并根据字母顺序选择"赢家":

// use "from player 1 to player 2" relation as key
foreach ($relations as $r) $relation_pairs[$r['from'].'+'.$r['to']] = $r; 
// pick the "winners" according to alphabetic order
ksort ($relation_pairs);
// merge relations
while (list($k,$r) = each($relation_pairs)) // this will take elements deletion into account immediately, contrary to foreach
{
    $symetric = $r['to'].'+'.$r['from'];
    if (isset($relation_pairs[$symetric])) // found a symetric relation
    {
        foreach ($relation_pairs[$symetric] as $field=>$value) // combine all numeric fields
            if (is_numeric ($value)) 
                $relation_pairs[$k][$field] -= $value;
        unset ($relation_pairs[$symetric]); // get rid of symetric relation
    }
}
$compressed_relations = array_values ($relation_pairs); // get rid of keys