【问题标题】:Use Generators as multidimensional array replacement使用生成器作为多维数组替换
【发布时间】:2015-09-17 01:28:41
【问题描述】:

前段时间我构建了一个工具,有人告诉我使用生成器而不是简单的数组来获得更好的性能等。我开始使用生成器,但是,谷歌搜索生成器的问题是非常无用的,因为没有发电机的很多信息。那么,让我们来回答我的问题

让我们想象下面的代码

$array  = [0, 1, 2, 3, 4, 5];
$mapper = ['zero', 'one', 'two', 'three', 'four', 'five'];

function mapNumbers($array, $mapper)
{
    foreach ($array as $element) {
        yield $element => $mapper[$element];
    }
}

foreach (mapNumbers($array, $mapper) as $key=>$value) {
    print $key . ' | ' . $value . '<br>';
}

这给出了以下输出

0 | zero
1 | one
2 | two
3 | three
4 | four
5 | five

但是,我现在想做的是一个多维数组。让我们想象一下

$categories = ['food', 'nonfood'];
$products   = ['food' => ['meat', 'fish'], 'nonfood' => ['table', 'stool']];

function mapCategories($categories, $products)
{
    foreach ($categories as $category) {
        yield 'Category' => $category, 'Products' => $products[$category]
    }
}

foreach (mapCategories($categories, $products) as $key=>$value) {
    // do something
}

这当然行不通,因为这行会报错

yield 'Category' =&gt; $category, 'Products' =&gt; $products[$category]

我正在尝试使用生成器来实现吗?第一次学习生成器时,我认为生成器可以在某些情况下替换数组,但在尝试构建多维数组时,它们似乎并没有替换数组。

这可能吗?如果是,如何?如果不是,我将如何将它与生成器结合起来?还是只有生成器还是只有数组?

非常感谢

【问题讨论】:

  • 您真正希望从食品/非食品示例中看到什么输出?你认为肉、鱼、桌子、凳子是四种不同的反应吗?钥匙应该是什么?食物/非食物?
  • PHP7 之前的生成器不容易实现。然后您可以使用yield from 创建递归样式的行为。因此,在 PHP5 上,通过替换调用堆栈就地仿真的递归仍然是可能的,但我不会那样做。当然,如果只是“使用生成器” - 这是一个坏主意
  • @MarkBaker 老实说,我希望得到与数组相同的输出,但为此使用 yield/generators。因此,与我执行 $return[] = ['Category' =&gt; $category, 'Products' =&gt; $prodcuts[$category] 时的输出相同,并且在 foreach 返回之后。我希望在使用生成器时有相同的输出
  • 很清楚,您在这里使用生成器的方式并不比直接遍历数组更好。因为无论如何你在内存中都有数组。像 for ($i = 0; $i &lt; 1000; $i++) yield $i; 这样的生成器会比数组 [0, 1, 2, ... 999] 更好,但是迭代一个本身只是迭代一个数组的生成器是非常荒谬的。
  • ideone.com/TFUeER 这样的东西(如果为了可读性而正确格式化)在这种情况下比使用生成器更有效,因为对于你的情况,唯一真正的好处是可读性之一

标签: php arrays multidimensional-array generator


【解决方案1】:

虽然您可以使用生成器来实现您想要的:

$categories = ['food', 'nonfood'];
$products   = ['food' => ['meat', 'fish'], 'nonfood' => ['table', 'stool']];

function mapCategories($categories, $products) {
    foreach ($categories as $category) {
        yield ['Category' => $category, 'Products' => $products[ $category]];
    }
}

foreach (mapCategories($categories, $products) as $key=>$value) {
    echo $key, ' => '; var_dump($value); echo PHP_EOL;
}

除了代码的可读性之外,这样做并没有真正的好处。生成器的真正好处是当您主动检索/动态生成数据时,当您获得仅在实际需要时保存所需数据的内存优势时,并且这样做可能更快。 简单地重新映射您已经加载到 PHP 内存中的数据不会带来任何速度或内存优势。

在您的情况下,简单地使用 array_map() 重新映射数据可以提供您想要的合并结构,同时仍保持良好的可读性:

$categories = ['food', 'nonfood'];
$products   = ['food' => ['meat', 'fish'], 'nonfood' => ['table', 'stool']];

foreach (
    array_map(
        function ($value) use ($products) {
            return ['Category' => $value, 'Products' => $products[$value]];
        },
        $categories
    ) as $value) {
        var_dump($value);
}

【讨论】:

    【解决方案2】:

    我想你想要的如下:

    $categories = ['food', 'nonfood'];
    $products   = ['food' => ['meat', 'fish'], 'nonfood' => ['table', 'stool']];
    
    function mapCategories($categories, $products)
    {
        foreach ($categories as $category) {
            foreach ($products as $product) {
                yield $category => $product;
            }
        }
    }
    
    # OR 
    
    function mapCategories($categories, $products)
    {
        foreach ($categories as $category) {
            yield $category => $products[$category];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 2013-08-28
      • 2016-01-20
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 2017-05-11
      相关资源
      最近更新 更多