如何优雅的重组两个数组的数据

例如:
我有两个数组,

$users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];
$list = [
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
];

预期:

$data = [
    [
        "id" => 1,
        "name" => "a",
        "list" => [
            ["user_id" => 1, "option" => 10],
            ["user_id" => 1, "option" => 11],
            ["user_id" => 1, "option" => 12]
        ]
    ],
        [
        "id" => 2,
        "name" => "b",
        "list" => [
            ["user_id" => 2, "option" => 10],
            ["user_id" => 2, "option" => 11],
            ["user_id" => 2, "option" => 12],
        ]
    ]
];

问题1:请问如何做到上述期望?
问题2:一条where in语句的时间复杂度和foreach分别去查的时间复杂度是否一致,哪种比较规范?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案
1、 $users = array_column($users,null,"id");
    array_walk($list,function ($item) use (&$users) {
        if (array_key_exists($item["user_id"],$users))
            $users[$item["user_id"]]["list"][] = $item;
    });
    $users = array_values($users);
2、wherein,一条 SQL 能解决的,尽量不用多个 SQL。不过我觉得最优方案应该是用 join 关联查询
3年前 评论
她来听我的演唱会 (楼主) 3年前
讨论数量: 21

如果这数据都在库里,直接做个关联就好了。

如果不在↓

 $users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];
$list = collect([
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
])->groupBy('user_id');

$users = collect($users)->map(function ($user) use ($list) {
    $user['list'] = $list->get($user['id'], collect())?->toArray();

    return $user;
});

dd($users->all());
3年前 评论
她来听我的演唱会 (楼主) 3年前

额,这不就是一对多关联么?

public function list()
{
    return hasMany...;
}
$q->whereIn('id',[1,2])->with('list')

这不就是你想要的数据了么? :joy:

要是我就分两个查询来,先查用户数组

whereIn('user_id', $ids)->groupBy('user_id')

然后再塞到用户数组里面去

3年前 评论
她来听我的演唱会 (楼主) 3年前
1、 $users = array_column($users,null,"id");
    array_walk($list,function ($item) use (&$users) {
        if (array_key_exists($item["user_id"],$users))
            $users[$item["user_id"]]["list"][] = $item;
    });
    $users = array_values($users);
2、wherein,一条 SQL 能解决的,尽量不用多个 SQL。不过我觉得最优方案应该是用 join 关联查询
3年前 评论
她来听我的演唱会 (楼主) 3年前

一:我觉得foreach重组就行了,代码要写的别人也尽量看的明白,可能我在很多时候会选择这样做。当然用的地方多可以封装成函数。
二:使用whereIn,foreach在执行多条语句的速度下是要慢很多的。

3年前 评论
mostwin 3年前
她来听我的演唱会 (楼主) 3年前
我爱大可乐 3年前
$users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];
$list = [
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
];

$newList = [];
foreach($list as $v) {
    $newList[$v['user_id']][] = $v;
}
foreach($users as &$user) {
    $user['list'] = isset($newList[$user['id']]) ? $newList[$user['id']] : [];
}
unset($user);

print_r($users);
3年前 评论
她来听我的演唱会 (楼主) 3年前

怎么简单,怎么方便,就怎么来,调用封装好的api,估计也是循环组装的数据

3年前 评论

不说数据量,单纯聊时间复杂度没啥意义,而且如果真的数据量巨大的话,可能要考虑换中思路去处理了。

$users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];

$list = [
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
];

$list = collect($list)->groupBy('user_id');
$users = collect($users)->map(function ($user) use ($list) {
    $user['list'] = $list->pull($user['id'])->toArray();
    return $user;
});

dd($list, $users->toArray());

file

没理解你这个 whereIn 的意思,如果是关联查询的话,本质上也是两条查询语句,然后 Eloquent 层利用 Collection 通过类似上述的方法实现的关联。

3年前 评论
她来听我的演唱会 (楼主) 3年前
  • 把每件事抽离出来,应该可以达到优雅的要求.
  • 这里包含两个事: 1.筛选 2 是组装.

代码如下:

// 用Id,筛选用户数组.
$getUserArr = function($userId) use($list) {
    return array_filter($list, function($item) use ($userId ) {
        return $item['user_id'] === $userId;
    });
};

// 给数据添加一个 list 
$data = array_map(function($item) use ($getUserArr) {
    $item['list'] = $getUserArr($item['id']);
    return $item;
}, $users);
3年前 评论
她来听我的演唱会 (楼主) 3年前
$users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];

$list = [
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
];
// 一般这么写,简单明了
foreach ($users as &$user) {
    $user['list'] = [];
    foreach ($list as $item) {
        $user['id'] == $item['user_id'] && $user['list'][] = $item;
    }
}

var_dump($users);
3年前 评论
她来听我的演唱会 (楼主) 3年前

既然是要优雅,当然是越少的内存和循环越好,这么写只有两个循环且无循环嵌套,内存占用也小


$users = [
    ["id" => 1, "name" => "a"],
    ["id" => 2, "name" => "b"]
];
 $list = [
    ["user_id" => 1, "option" => 10],
    ["user_id" => 1, "option" => 11],
    ["user_id" => 1, "option" => 12],
    ["user_id" => 2, "option" => 10],
    ["user_id" => 2, "option" => 11],
    ["user_id" => 2, "option" => 12]
];

$pointers=[];

foreach ($users as &$user){
    $pointers[$user['id']]=[];
    $user['list']=&$pointers[$user['id']];
    unset($user);
}

foreach ($list as $item){
    $pointers[$item['user_id']][]=$item;
}

print_r($users);
3年前 评论

$users = array_column($users, null, 'id');

array_walk($list, function ($item) use (&$users) {
    if ( $users[$item['user_id']] ?? false ) {
        $users[$item['user_id']]['list'][] = $item;
    }
});
unset($list);
var_dump($users);
{
    "1": {
        "id": 1,
        "name": "a",
        "list": [
            {
                "user_id": 1,
                "option": 10
            },
            {
                "user_id": 1,
                "option": 11
            },
            {
                "user_id": 1,
                "option": 12
            }
        ]
    },
    "2": {
        "id": 2,
        "name": "b",
        "list": [
            {
                "user_id": 2,
                "option": 10
            },
            {
                "user_id": 2,
                "option": 11
            },
            {
                "user_id": 2,
                "option": 12
            }
        ]
    }
}

isset()要比 array_key_exists()好点

问题2:需要看情况,如果表不大查询数据不大 一条sql查询出来最好了,反之就是分批次查询(不能是直接请求的,可以用定时任务,队列来处理)

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!