在嵌套的foreach中替换数组值?

时间:2017-07-24 02:43:24

标签: php arrays foreach

我有一个简单的函数,可以将静态值数组($ type)与动态值($ inventory)进行比较,并且如果找不到则将值0添加到数组中。问题似乎与第二个foreach中的条件有关,不知何故它覆盖了这些值。

例如。如果我在if中的第一次迭代中返回数组,我会得到我期望的值。但是,如果我在所有循环完成后返回数组,我只为每个元素得到0值。

这是功能。

function buildDriveInventory($inventory) {   
  $type = [1, 2, 4, 6, 8, 10, 12, 14, 16];
  $unit = "lbs";

  //create new array to hold values        
  $new_values = [];

  foreach ($type as $type_value) {
    foreach ($inventory as $product) {
      if ($type_value === $product['capacity']) {
        $new_values[$product['capacity'].$product['unit']] = $product['total'];
      } else {
        $new_values[$type_value.$unit] = 0;
      }
    }
  }

  return $new_values;

}

以下是inventory数组的示例,以及我需要new_values包含的内容。

array(7) { 
  [0]=> array(3) { 
    ["capacity"]=> int(1) ["unit"]=> string(2) "lbs" ["total"]=> int(6) 
  } 
  [1]=> array(3) { 
    ["capacity"]=> int(2) ["unit"]=> string(2) "lbs" ["total"]=> int(1) 
  } 
  [2]=> array(3) { 
    ["capacity"]=> int(4) ["unit"]=> string(2) "lbs" ["total"]=> int(2) 
  } 
  [3]=> array(3) { 
    ["capacity"]=> int(6) ["unit"]=> string(2) "lbs" ["total"]=> int(4) 
  } 
  [4]=> array(3) { 
    ["capacity"]=> int(8) ["unit"]=> string(2) "lbs" ["total"]=> int(4) 
  } 
  [5]=> array(3) { 
    ["capacity"]=> int(10) ["unit"]=> string(2) "lbs" ["total"]=> int(2) 
  } 
  [6]=> array(3) { 
    ["capacity"]=> int(12) ["unit"]=> string(2) "lbs" ["total"]=> int(2) 
  } 
}

array(9) { 
  ["1lbs"]=> int(6) 
  ["2lbs"]=> int(1) 
  ["4lbs"]=> int(2) 
  ["6lbs"]=> int(4) 
  ["8lbs"]=> int(4) 
  ["10lbs"]=> int(2) 
  ["12lbs"]=> int(2) 
  ["14lbs"]=> int(0) 
  ["16lbs"]=> int(0)
}

4 个答案:

答案 0 :(得分:0)

根据你的代码,一切都很好。只需在if块中使用中断语句。

if ($type_value === $product['capacity']) {
     $new_values[$product['capacity'].$product['unit']] = $product['total'];
     break;
} 

完整代码如下。

function buildDriveInventory($inventory) {   
  $type = [1, 2, 4, 6, 8, 10, 12, 14, 16];
  $unit = "lbs";

  //create new array to hold values        
  $new_values = [];

  foreach ($type as $type_value) {
    foreach ($inventory as $product) {
      if ($type_value === $product['capacity']) {
        $new_values[$product['capacity'].$product['unit']] = $product['total'];
        break;
      } else {
        $new_values[$type_value.$unit] = 0;
      }
    }
  }

  return $new_values;

}

答案 1 :(得分:0)

只是为了展示不同风格的方法,你可以这样写:

代码:(Demo

IF OBJECT_ID('tempdb..#TreeData', 'U') IS NOT NULL 
DROP TABLE #TreeData;

CREATE TABLE #TreeData (
    Id INT NOT NULL,
    SomeName VARCHAR(3) NOT NULL,
    ParentId INT NULL 
    );
INSERT #TreeData (Id, SomeName, ParentId) VALUES 
    (1, 'O', NULL),
    (2, 'D1', 1),
    (3, 'D2', 1),
    (4, 'S1', 2),
    (5, 'S2', 2),
    (6, 'S1', 3),
    (7, 'SP1', 3);

--SELECT * FROM #TestData td;

;With Cte as (   --Recursive CTE for traversing tree
    Select Id,SomeName,ParentId, convert(varchar(max),[SomeName]) as NameLevel, 1 as Levl from #TreeData where ParentId is Null
    Union all
    Select t.Id, t.[SomeName], t.[ParentId],  (c.NameLevel +','+ t.[SomeName]) as NameLevel, c.Levl + convert(int, 1) as Levl 
     from Cte c
          inner join #TreeData t on c.Id = t.ParentId
)
--select * from cte
Select * from ( 
    select c.Id, c.Levl, a.Items
    ,RowN = row_number() over(partition by Id order by Levl) from cte c
    cross apply  split(c.NameLevel,',') a
) sq
pivot(max([Items]) for RowN in([1],[2],[3])) p --Pivot for getting all data

输出:

function buildDriveInventory($inventory,$unit='lbs',$type=[1,2,4,6,8,10,12,14,16]){
    array_walk($type,function($v)use($unit,&$defaults){$defaults["$v$unit"]=0;});
    array_walk($inventory,function($a)use(&$new_inventory){$new_inventory[$a['capacity'].$a['unit']]=$a['total'];});
    return array_replace($defaults,$new_inventory);
}
$inventory=[
    ["capacity"=>1,"unit"=>"lbs","total"=>6],
    ["capacity"=>2,"unit"=>"lbs","total"=>1],
    ["capacity"=>4,"unit"=>"lbs","total"=>2],
    ["capacity"=>6,"unit"=>"lbs","total"=>4],
    ["capacity"=>8,"unit"=>"lbs","total"=>4],
    ["capacity"=>10,"unit"=>"lbs","total"=>2],
    ["capacity"=>12,"unit"=>"lbs","total"=>2]
];
var_export(buildDriveInventory($inventory));

这允许您直接在调用中编写array ( '1lbs' => 6, '2lbs' => 1, '4lbs' => 2, '6lbs' => 4, '8lbs' => 4, '10lbs' => 2, '12lbs' => 2, '14lbs' => 0, '16lbs' => 0, ) $unit数据,但该函数在省略时使用默认值。也许这种灵活性很有用,也许不是。

使用$type生成两个准备好的数组的行为与foreach循环的行为相同。

使用array_walk()完成if语句的工作,并避免在每次迭代时调用array_replace()。在这种情况下,in_array()具有相同的效果,但“替换”更直接/直观地说明正在执行的过程。我不知道哪个函数执行得更快,但可能是几纳秒的差异。

P.S。为了记录,array_merge()在提供的输入数据上具有相同的准确度(并且可能是最快的),但我没有在其他数据集上测试它。

答案 2 :(得分:-1)

你的代码会在第一个数组的每一轮分配第二个数组,我想你想要这样:

foreach ($inventory as $k =>$product) {
    if ($type[$k] === $product['capacity'])) {
        $new_values[$product['capacity'].$product['unit']] = $product['total'];
    } else {
        $new_values[$type[$k].$unit] = 0;
    }
}

答案 3 :(得分:-1)

请改为尝试:

conda create -n py35 python=3.5
activate py35
conda install -c macinv blpapi