【问题标题】:Multiple values to one key from 2 arrays in PHPPHP中2个数组的一个键的多个值
【发布时间】:2018-07-24 13:27:37
【问题描述】:

我想将 2 个数组与 array_combine 结合起来。我希望 Array1 的值是我的键,而 Array2 的值​​是我的值。 这些值来自一个 .yml 文件,其中 componentgroup 作为 Key,componentname 作为 Value

   $yamlKeys = array();
    foreach ($yaml['components'] as $yamlComponent) {
        array_push($yamlKeys, $yamlComponent['cachet']['componentgroup']);
    }

    $yamlValues = array();
    foreach ($yaml['components'] as $yamlComponent) {
        array_push($yamlValues, $yamlComponent['cachet']['componentname']);
    }

    $yamlMap = array();
    $yamlMap = array_combine($yamlKeys, $yamlValues);

    echo("===== YAML MAP STARTS =====");
    var_dump($yamlMap);
    echo("===== YAML MAP ENDS =====");  

我的问题: 可以有同名的键。 在 $yamlMap 中只会分配一个值(最后一个)。例如:

Yaml 文件如下所示:

FOO => BAR
Key1 => Value1
Key2 => Value2
FOO => BAZ
Key3 => Value3  

我的代码可以:

FOO => BAZ
Key1 => Value1
Key2 => Value2
Key3 => Value3  

但我想要这样:

FOO => BAR, BAZ
Key1 => Value1
Key2 => Value2
Key3 => Value3  

更准确地说:如果有更多“FOO”键,我希望“FOO”有更多值(可能是一个值数组)。

有什么想法吗?谢谢。

【问题讨论】:

  • 在您的输出中,您想要一个逗号分隔的字符串'BAR, BAZ' 还是一个包含两个元素['BAR', 'BAZ'] 的数组?您希望Value1 是一个字符串还是包含一个字符串的数组?由于您接受了答案,我觉得您的问题不清楚。
  • 我写了“如果有更多的“FOO”键,我希望“FOO”有更多的值(可能是一个值数组)。所以是的,我希望该值是一个数组。抱歉表达不清楚。
  • 您希望 Key1 指向一个字符串还是包含单个字符串的数组?你表达的输出不清楚。
  • 如果它是一个带有字符串 value1 的数组,那么我同意,问题不清楚。此外,无论是否使用 if() 部分,接受的答案都会给出完全相同的输出
  • 这不是问题所在。在您的示例中,Key1 => Value1 是什么。它是一个字符串还是一个数组。例如["key1" => "value1"]["key1" => ["value1"]] 这是一个很大的区别。我个人更喜欢选项 2,因为它始终是相同的数组结构。但你的问题是选项 1

标签: php arrays dictionary key key-value


【解决方案1】:

您的代码不起作用的原因是 array_combine 需要唯一键。因此,循环是获得预期值的唯一方法。

这是我循环唯一键并使用 array_intersect(_key) 获取匹配值的一种方法。
如果计数大于一,我知道输出子数组应该是一个数组。
否则它是 [0] 项中的单个值(因为 array_values),我只是添加它。

$yamlKeys = ["FOO","Key1","Key2","FOO","Key3"];
$yamlValues = ["BAR","Value1","Value2","BAZ","Value3"];

$yamlMap = [];
foreach(array_unique($yamlKeys) as $key => $ykey){
    $temp = array_values(array_intersect_key($yamlValues,array_intersect($yamlKeys, [$ykey])));
    if(count($temp)>1){
        $yamlMap[$ykey] = $temp;
    }else{
        $yamlMap[$ykey] = $temp[0];
    }
}

var_dump($yamlMap);

输出:

array(4) {
  ["FOO"]=>
  array(2) {
    [0]=>
    string(3) "BAR"
    [1]=>
    string(3) "BAZ"
  }
  ["Key1"]=>
  string(6) "Value1"
  ["Key2"]=>
  string(6) "Value2"
  ["Key3"]=>
  string(6) "Value3"
}

https://3v4l.org/hu2re

由于“问题”是 FOO 键,我将解释代码对该键的作用。

代码使用array_intersect查找“FOO”键并返回:

array(2) {
  [0]=>
  string(3) "FOO"
  [3]=>
  string(3) "FOO"
}

请注意键与您的原始数组匹配。
这在 array_intersect_key 中使用,它使用键编号并从具有匹配键的值数组中获取值。

array(2) {
  [0]=>
  string(3) "BAR"
  [3]=>
  string(3) "BAZ"
}

然后我使用 array_values 将键设置为 0、1。
$temp 现在看起来像

array(2) {
  [0]=>
  string(3) "BAR"
  [1]=>
  string(3) "BAZ"
}

由于计数大于一,if() 将为真,并且 $temp-array 被添加到 $yamlMap 的键“FOO”中。
如果它只是数组中的一项,则只会添加单个字符串,因此不是多维的

【讨论】:

  • 这正是我所寻找的。我需要很长时间才能理解它,但它确实有效。非常感谢,安德烈亚斯。
  • 我会尝试在代码中添加一些 cmets 使其更清晰
  • 这是金子。谢谢安德烈亚斯!
  • @Andreas 我有足够的耐心。我投票不清楚。
【解决方案2】:

这是一种更直接的方法:

代码:(Demo) (or this alternative/condensed version)

$yamlMap = [];
foreach ($yaml['components'] as $yamlComponent) {
    $key = $yamlComponent['cachet']['componentgroup'];
    $value = $yamlComponent['cachet']['componentname'];
    if (isset($yamlMap[$key])) {
        if (is_array($yamlMap[$key])) {
            $yamlMap[$key][] = $value;  // push to existing array
        } else {
            $yamlMap[$key] = [$yamlMap[$key], $value];  // convert string to array containing old string and new string
        }
    } else {
        $yamlMap[$key] = $value;  // save first occurrence as a string
    }
}

var_export($yamlMap);

输出:

array (
  'FOO' => 
  array (
    0 => 'BAR',
    1 => 'BAZ',
  ),
  'Key1' => 'Value1',
  'Key2' => 'Value2',
  'Key3' => 'Value3',
)

初步解决方案:

遍历您的数据一次,将其归结为一个二维数组,然后使用array_merge_recursive() 的魔法将其转换为您想要的输出。 ... 是 splat 运算符,它告诉 array_merge_recursive()$result 视为一系列 1-dim 数组而不是 2-dim 数组。

代码:(Demo)

foreach ($yaml as $components) {
    foreach ($components as $sets) {
        foreach ($sets as $cachet) {
            $result[] = [$cachet['componentgroup'] => $cachet['componentname']];
        }
    }
}

var_export(array_merge_recursive(...$result));

我的解决方案从您未触及的$yaml 变量开始。

$yaml = [
    'components' => [
        [
            'cachet' => [
                'componentgroup' => 'FOO',
                'componentname' => 'BAR'
            ]
        ],
        [
            'cachet' => [
                'componentgroup' => 'Key1',
                'componentname' => 'Value1'
            ]
        ],
        [
            'cachet' => [
                'componentgroup' => 'Key2',
                'componentname' => 'Value2'
            ]
        ],
        [
            'cachet' => [
                'componentgroup' => 'FOO',
                'componentname' => 'BAZ'
            ]
        ],
        [
            'cachet' => [
                'componentgroup' => 'Key3',
                'componentname' => 'Value3'
            ]
        ]
    ]
];

输出:

array (
  'FOO' => 
  array (
    0 => 'BAR',
    1 => 'BAZ',
  ),
  'Key1' => 'Value1',
  'Key2' => 'Value2',
  'Key3' => 'Value3',
)

【讨论】:

  • @Juri_Wolkow 你明白我的意思吗?
  • 不幸的是没有。我应该提到我实际上不是 PHP 开发人员,但我现在必须在 PHP 中做一些事情。不过,我真的很感谢你的帮助,米克!
  • 您的问题是执行循环只是为了设置键数组和值数组。我从头开始并更改了您的流程以设置array_merge_recursive() 的使用,它在重复键时自然构建子数组。我的回答是非常“功能轻”/高效。
【解决方案3】:
$yamlMap = [];
foreach ($yaml['components'] as $yamlComponent) {
    $key = $yamlComponent['cachet']['componentgroup'];
    $value = $yamlComponent['cachet']['componentname'];
    // Lets initialize the key to be an array so that we may collect multiple values
    if(!array_key_exists($key, $yamlMap)) {
        $yamlMap[$key] = [];
    }
    // lets add the value to the map under the key
    $yamlMap[$key][] = $value;
}

https://3v4l.org/FtjQC

【讨论】:

  • 这根本没有帮助。我纠正了语法错误并得到了相同的结果(只是最后一个值被分配给键,但不是两者)
  • @Juri_Wolkow 现在试试,我翻转了array_key_exists 的参数并修复了语法错误。我已经有一段时间没有写 PHP 了。
  • @Juri_Wolkow 你被骗了。这个答案不会提供您想要的输出。 3v4l.org/SsqCX
猜你喜欢
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-17
相关资源
最近更新 更多