使用 Foreach PHP 将记录正确地分配给正确的父级

properly assign records into correct parent using foreach php

提问人:melvnberd 提问时间:8/11/2023 更新时间:8/11/2023 访问量:54

问:

我有一个类似的数组,如下所示:

       $agents = [
          (object)["id"=> 301,"name"=> "Agent 1"],
           (object)["id"=> 303,"name"=> "Agent 2"],
           (object)["id"=> 301,"name"=> "Agent 3"],
           (object)["id"=> 305,"name"=> "Agent 4"],
           (object)["id"=> 306,"name"=> "Agent 5"],
           (object)["id"=> 303,"name"=> "Agent 6"]
        ];


         $locations =  [
             (object)["xid"=> 148,"location_name"=> "USA"],
             (object)["xid"=> 149,"location_name"=> "CHINA"],
             (object)["xid"=> 153,"location_name"=> "GERMANY"],
             (object)["xid"=> 156,"location_name"=> "CANADA"],
             (object)["xid"=> 167,"location_name"=> "SINGAPORE"],
             (object)["xid"=> 0,"location_name"=> "No Location"]
        ];

       
        $records = [
           (object)["agent_id"=> 301,"location_id"=> 156,"total"=> 10000],
           (object)["agent_id"=> 303,"location_id"=> 149,"total"=> 13000],
           (object)["agent_id"=> 301,"location_id"=> 156,"total"=> 10000],
           (object)["agent_id"=> 305,"location_id"=> 0,"total"=> 10000],
           (object)["agent_id"=> 306,"location_id"=> 148,"total"=> 10000],
           (object)["agent_id"=> 303,"location_id"=> 0,"total"=> 10000]
        ];

我正在尝试将正确的事务分配到 $agent->locations->transactions 中,但我的循环不起作用。

        foreach ($agents as $a) {
            foreach ($locations as $l) {
                $a->locations[]=$l;
                foreach ($records as $r) {
                    if($r->location_id == $l->xid && $r->agent_id == $a->id){
                        $l->transactions[] = $r;
                    }
                }
            }
        }

这是结果

enter image description here

我试图实现的是,交易应该在正确的代理下分配/过滤。请帮忙..在那个循环上看了太久,不知道如何实现我需要:(......

enter image description here

PHP 数组 对象 foreach

评论

0赞 Barmar 8/11/2023
最好将数组转换为关联数组。这样你就不需要所有这些嵌套的循环了,你可以把它们索引起来。
0赞 melvnberd 8/11/2023
嗨,@Barmar tnx 停下来,您能否进一步详细说明我将如何正确转换它们?
0赞 Barmar 8/11/2023
foreach ($agents as $a) { $agents_assoc[$a->id] = $a; }
1赞 Barmar 8/11/2023
但是,由于每个代理都包含所有位置,因此当您修改某个位置的交易列表时,该列表将显示在所有代理下,而不仅仅是具有相同agent_id的代理。您不是在克隆位置对象,它们都是对同一对象的引用。
1赞 Barmar 8/11/2023
在 PHP 中,对象是通过引用传递的,数组是复制的(除非你用来制作引用变量)。&

答:

1赞 Abdulla Nilam 8/11/2023 #1

您应该:

  1. 为每个代理创建一个位置属性。
  2. 在浏览记录时,弄清楚交易属于哪个代理和位置。然后,将交易放在正确代理下的正确位置。

$agentIndex = [];
$locationIndex = [];

// moving to the index to quick lookup.
foreach ($agents as $agent) {
    $agent->locations = [];
    $agentIndex[$agent->id] = $agent;
}

foreach ($locations as $location) {
    $location->transactions = [];
    $locationIndex[$location->xid] = $location;
}


foreach ($records as $record) {
    $agent = $agentIndex[$record->agent_id] ?? null;
    $location = $locationIndex[$record->location_id] ?? null;

    if ($agent && $location) {
        // Add location to the agent does not exist
        if (!isset($agent->locations[$location->xid])) {
            $agent->locations[$location->xid] = $location;
        }
        $agent->locations[$location->xid]->transactions[] = $record;
    }
}

// mapping again with an indexed array
foreach ($agents as $agent) {
    $agent->locations = array_values($agent->locations);
}

print_r($agents);

将位置移到了前膛内。

$agentIndex = [];
$locationIndex = [];

foreach ($agents as $agent) {
    $agent->locations = [];
    $agentIndex[$agent->id] = $agent;
}

foreach ($locations as $location) {
    $locationIndex[$location->xid] = $location;
}

foreach ($records as $record) {
    $agent = $agentIndex[$record->agent_id] ?? null;
    
    if (isset($locationIndex[$record->location_id])) {
        $location = clone $locationIndex[$record->location_id];
    } else {
        $location = null;
    }

    if ($agent && $location) {
        if (!isset($agent->locations[$location->xid])) {
            $location->transactions = [];  
            $agent->locations[$location->xid] = $location;
        }
        $agent->locations[$location->xid]->transactions[] = $record;
    }
}


foreach ($agents as $agent) {
    $agent->locations = array_values($agent->locations);
}

print_r($agents);

评论

0赞 Barmar 8/11/2023
不要只是发布代码,解释出了什么问题以及如何修复它。
0赞 melvnberd 8/11/2023
感谢 Nilam @Abdulla代码。.是的,你的解释是我真正需要做的..但我只是不知道如何实现它......现在我尝试了您的代码并试图了解您的工作,它几乎是完美的,但我看到了不属于正确代理的记录..pasteboard.co/WYrsc7S5dx4W.png
1赞 Abdulla Nilam 8/11/2023
@melvnberd检查编辑
0赞 melvnberd 8/11/2023
很抱歉打扰了,从那以后就没有使用过方法..现在我得到了clone__clone method called on non-object
0赞 melvnberd 8/11/2023
我真的很感激抽出时间并帮助@Abdulla Nilam爵士。我几乎让它工作了..我的代码中唯一缺少的实际上是那个东西。无论如何,我尝试了您的代码,但我收到了错误,@nice_dev先生的回答很短,并没有真正更改我的代码。clone
1赞 nice_dev 8/11/2023 #2

您正在处理对象。因此,对它所做的任何修改都将在以后反映出来。

你做到了.因此,现在该对象也将具有以前的交易详细信息。$l->transactions[] = $r;$l

要解决此问题,您可以创建对象的快速克隆,并使用克隆修改此新对象。

片段:

<?php

foreach($agents as $agent){
    $agent->locations = [];
    foreach($locations as $location){
        $location = clone $location;
        $location->transactions = [];
        foreach($records as $r){
            if($r->agent_id == $agent->id && $location->xid == $r->location_id){
                $location->transactions[] = $r;
            }
        }
        
        $agent->locations[] = $location;
    }
}

现场演示