使用哪个PHP数组函数?

huangapple go评论65阅读模式
英文:

Which PHP Array Function to Use?

问题

我在所有不同的PHP数组函数之间感到非常困惑,我不知道在我的情况下哪个是最好的选择。

我有一个数组列出了用户的注册信息,还有一个数组列出了这些用户的订阅信息以及用户订阅的日期。用户可以有多个订阅,也可能没有订阅。例如:

$users = [
    ['user_id' => 1, 'sign_up_date' => '2020-01-01 00:00:00'],
    ['user_id' => 2, 'sign_up_date' => '2020-01-02 00:00:00'],
    ['user_id' => 3, 'sign_up_date' => '2020-01-03 00:00:00'],
    // ...
];

$subscriptions = [
    ['user_id' => 1, 'subscription_category' => 'abc', 'sign_up_date' => '2020-01-01 00:01:00'],
    ['user_id' => 1, 'subscription_category' => 'def', 'sign_up_date' => '2020-01-01 00:02:00'],
    ['user_id' => 1, 'subscription_category' => 'ghi', 'sign_up_date' => '2020-01-02 00:03:00'],
    ['user_id' => 2, 'subscription_category' => 'jkl', 'sign_up_date' => '2020-01-02 00:01:00'],
    ['user_id' => 2, 'subscription_category' => 'mno', 'sign_up_date' => '2020-01-03 00:02:00'],
    // ...
];

我试图找到哪些用户在他们注册日期当天订阅了任何类别。所以在这种情况下,我想找到以下数组中的项目数量:

$usersWhoSubscribedOnSignUpDate = [1, 2];

我可以做以下操作:

$results = [];
foreach ($users as $user) {
    foreach ($subscriptions as $subscription) {
        $signUpDate = date('Y-m-d', strtotime($user['sign_up_date']));
        $subscriptionDate = date('Y-m-d', strtotime($subscription['sign_up_date']));

        if ($subscription['user_id'] === $subscription['user_id'] && $signUpDate === $subscriptionDate) {
            $results[] = $subscription['user_id'];
        }
    }
}
$results = array_unique($results);

但在我看来,这不是很优雅,我相信许多PHP数组函数中的一个可以以某种方式简化这个过程。

array_intersect 似乎不适用,因为它似乎不适用于多级数组。

array_map 似乎不适用,因为它没有比较两个数组的能力。

array_uintersect_assoc 似乎可以是一个选项,但我无法理解"additional index check"是什么意思,也不知道如何对数据进行排序。我认为回调函数需要返回两个对象的比较,所以也许可以按照 sign_up_date 属性的时间戳来排序?

英文:

I'm getting super confused between all the different array functions in PHP and I have no idea which is best to use in my scenario.

I have one array that lists user sign ups and one array which lists subscriptions for those users with the date the user subscribed. The user can have multiple subscriptions or not at all. An example would be:

$users = [
    ['user_id' => 1, 'sign_up_date' => '2020-01-01 00:00:00'],
    ['user_id' => 2, 'sign_up_date' => '2020-01-02 00:00:00'],
    ['user_id' => 3, 'sign_up_date' => '2020-01-03 00:00:00'],
    ...
];

$subscriptions = [
    ['user_id' => 1, 'subscription_category' => 'abc', 'sign_up_date' => '2020-01-01 00:01:00'],
    ['user_id' => 1, 'subscription_category' => 'def', 'sign_up_date' => '2020-01-01 00:02:00'],
    ['user_id' => 1, 'subscription_category' => 'ghi', 'sign_up_date' => '2020-01-02 00:03:00'],
    ['user_id' => 2, 'subscription_category' => 'jkl', 'sign_up_date' => '2020-01-02 00:01:00'],
    ['user_id' => 2, 'subscription_category' => 'mno', 'sign_up_date' => '2020-01-03 00:02:00'],
    ...
];

What I'm attempting to find is which users subscribed to any category on their sign up date. So in this case I want to find the number of items in:

$usersWhoSubscribedOnSignUpDate = [1, 2];

What I could do is something like:

$results = [];
foreach ($users as $user) {
    foreach ($subscriptions as $subscription) {
        $signUpDate = date('Y-m-d', strtotime($user['sign_up_date']));
        $subscriptionDate = date('Y-m-d', strtotime($subscription['sign_up_date']));

        if ($subscription['user_id'] === $subscription['user_id'] && $signUpDate === $subscriptionDate) {
            $results[] = subscription['user_id'];
        }
    }
}
$results = array_unique($results);

But that's not very elegant in my eyes and I'm convinced that one of the many PHP array functions could simplify this process somehow.

array_intersect doesn't seem suitable because it doesn't appear to work with multi-level arrays like this.

array_map doesn't seem suitable because it doesn't have the ability to compare two arrays.

array_uintersect_assoc seems like it could be an option however I can't understand what the "additional index check" means or how to sort the data. I believe that the callback function needs to return a comparison between two objects so perhaps this could be sorted by timestamp of the sign_up_date property?

答案1

得分: 1

以下是翻译好的部分:

你可以在 $users 的一次迭代和 $subscriptions 的一次迭代中完成这个操作,而不是在 $users 的每一行中进行一次 $subscriptions 的迭代。随着行数的增加,这可能代表了显著的性能提升。

首先,建立一个以 user_id 为索引的用户注册日期的关联数组,这样你就不需要每次查找日期时都对其进行迭代:

$userDates = [];
foreach ($users as $user) {
    $userDates[$user['user_id']] = date('Y-m-d', strtotime($user['sign_up_date']));
}

这将给你:

Array
(
    [1] => 2020-01-01
    [2] => 2020-01-02
    [3] => 2020-01-03
)

然后只需一次迭代订阅,查找用户的注册日期:

foreach ($subscriptions as $subscription) {
    if (
        date('Y-m-d', strtotime($subscription['sign_up_date'])) ===
        $userDates[$subscription['user_id']]
    ) {
        // ...
    }
}

或者也可以尝试以下方式:

array_unique(array_filter(
    $subscriptions,
    function ($subscription) use ($userDates) {
        return date('Y-m-d', strtotime($subscription['sign_up_date'])) ===
            $userDates[$subscription['user_id']];
    }
));
英文:

You can do this in one iteration of $users and one iteration of $subscriptions, rather than one iteration of $subscriptions per row in $users. This could represent a significant performance improvement as the number of rows increase.

First, build an associative array of user signup dates indexed by user_id, so that you do not need to iterate over it every time you need to look up a date:

$userDates = [];
foreach ($users as $user) {
    $userDates[$user['user_id']] = date('Y-m-d', strtotime($user['sign_up_date']);
}

This will give you:

Array
(
    [1] => 2020-01-01
    [2] => 2020-01-02
    [3] => 2020-01-03
)

Then just iterate over the subscriptions once, looking up that user's signup date as you go:

foreach ($subscriptions as $subscription) {
    if (
        date('Y-m-d', strtotime($subscription['sign_up_date'])) ===
        $userDates[$subscription['user_id']]
    ) {
        ...
    }
}

Or perhaps something like:

array_unique(array_filter(
    $subscriptions,
    function ($subscription) use ($userDates) {
        return date('Y-m-d', strtotime($subscription['sign_up_date'])) ===
            $userDates[$subscription['user_id']];
    }
));

答案2

得分: 0

第一步我会修改你的数组,使用户通过键来识别(这是前两行)。第三行将订阅日期减少到每个用户的最早日期,然后第四行找到注册日期和最早订阅日期匹配的地方。

foreach( $users as $u ) { $signups[$u['user_id']] = date('Y-m-d', strtotime($u['sign_up_date']) ); }
foreach( $subscriptions as $s ) { $subs[$s['user_id']][] = date('Y-m-d', strtotime($s['sign_up_date']) ); }
foreach( $subs as $key => $value ) { $subs[$key] = min( $subs[$key] ); }
$results = array_keys( array_intersect_assoc( $signups, $subs ) );
英文:

The first think I would do is modify your arrays so the users are identified by keys, (that's the first two lines). The third line reduces the subscription dates to the earliest for each user, then the fourth finds places where the sign up and earliest subscription dates match.

foreach( $users as $u ) { $signups[$u['user_id']] = date('Y-m-d', strtotime($u['sign_up_date']) ); }
foreach( $subscriptions as $s ) { $subs[$s['user_id']][] = date('Y-m-d', strtotime($s['sign_up_date']) ); }
foreach( $subs as $key => $value ) { $subs[$key] = min( $subs[$key] ); }
$results = array_keys( array_intersect_assoc( $signups, $subs ) );

huangapple
  • 本文由 发表于 2020年1月4日 01:03:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/59582499.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定