动态合并数组的算法

Posted

技术标签:

【中文标题】动态合并数组的算法【英文标题】:Algorithm to dynamically merge arrays 【发布时间】:2012-01-25 09:10:29 【问题描述】:

我正在尝试为 phpExcel 对象中的每一行创建一个 INSERT 语句。由于我一直在努力遍历列(即转到 B1 C1 D1,获取值并将它们放入数组中),我选择获取每列的所有值并将它们放入多维如下所示的数组:

Array
(
    [foo] => Array
        (
            [0] => 250
            [1] => 247
            [2] => 279
            [3] => 249
        )

    [bar] => Array
        (
            [0] => AM PROV
            [1] => AM PROV
            [2] => AM PENS
            [3] => AM PROV
        )

    [schoo] => Array
        (
            [0] => xxxx
            [1] => yyy
            [2] => zzz
            [3] => aaa
        )
)

我想合并每个数组,以便索引 0 处的所有数据都在一个数组中,等等。我构建了一个通用工具,允许您从上传的电子表格中选择所需的列。它需要首先将列数据合并到一个数组中,然后它应该为每个数组生成 INSERT 语句。所以最终的成果是这样的:

INSERT INTO (foo, bar, schoo) VALUES (250, "AM PROV", "xxxx");

感谢所有帮助。

更新:大家好,非常感谢您的回答。根据马克的建议,我终于设法使用行和单元格迭代器使其工作并且它正在工作。我现在有一个单独的问题,但我认为这是我可以解决的问题。再次感谢。

【问题讨论】:

不熟悉php,但这不是二维数组[][]结构吗? @Kent 在 php 数组中是数组列表映射和几乎所有其他数据结构都整合到一个... 使用 PHPExcel 的行和单元格迭代器,甚至 rangeToArray() 方法获取所需的数组应该非常简单......你遇到了什么问题? @MarkBaker 我会再看一遍......但我无法弄清楚如何在两个方向上进行迭代。因此我的问题中的解决方案。 【参考方案1】:
<?php
$uberArray = array(
    "foo" => array(
        0 => 250,
        1 => 247,
        2 => 279,
        3 => 249,
    ),
    "bar" => array(
        0 => "AM PROV",
        1 => "AM PROV",
        2 => "AM PENS",
        3 => "AM PROV",
    ),
    "schoo" => array(
        0 =>  "xxxx",
        1 =>  "yyy",
        2 =>  "zzz",
        3 =>  "aaa",
    )
);

$yourmysqlLink = mysql_connect('localhost', 'user', 'pass');
mysql_query('SET NAMES utf8'); // Adjust according to your encoding

$colNames = array_keys($uberArray);
$stringCols = array('bar', 'schoo');
$sqlInsertStr = 'INSERT INTO `your_table` (`'.implode('`, `', $colNames)."`) VALUES \n";

$rows = array();
// Not really for iterating the first array, we just need a loop
foreach ($uberArray[$colNames[0]] as $k => $v) 
    $vals = array();
    foreach ($colNames as $v2) 
        $val = $uberArray[$v2][$k];
        if (in_array($v2, $stringCols)) 
            $val = "'".mysql_real_escape_string($val, $yourMysqlLink)."'";
        
        $vals[] = $val;
    
    $rows[] = "\t(".implode(', ', $vals).")";

$sqlInsertStr .= implode(",\n", $rows).';';

echo '<pre style="clear:both;">'.$sqlInsertStr.'</pre>'; ;

请注意,如果$uberArray 很大(例如,将插入字符串拆分为块),您可能需要出于性能原因进行一些调整。或者您可以将数据转换为 CSV 并使用 MySQL LOAD DATA INFILE 方法,速度非常快。

【讨论】:

【参考方案2】:

不确定这是不是你想要的,但是......

<?php
# Given this array
$arrays = array(
    'foo' => array(
        0 => 250, 
        1 => 247, 
        2 => 279, 
        3 => 249
    ), 
    'bar' => array(
        0 => 'AM PROV', 
        1 => 'AM PROV', 
        2 => 'AM PENS', 
        3 => 'AM PROV'
    ), 
    'schoo' => array(
        0 => 'xxxx', 
        1 => 'yyy', 
        2 => 'zzz', 
        3 => 'aaa'
    )
);

# This code generates...
$fields = array();
$inserts = array();

foreach ($arrays as $k => $v) 
    $fields[] = $k;


for ($i = 0; $i < count($arrays[$fields[0]]); $i++) 
    $vals = array();

    foreach ($fields as $field) 
        $vals[] = $arrays[$field][$i];
    

    $inserts[] = 'INSERT INTO (' . implode(',', $fields) . ') VALUES ("' . implode('","', $vals) . '")';


# This array
/* $inserts = array(
    'INSERT INTO (foo, bar, schoo) VALUES ("250", "AM PROV", "xxxx")', 
    'INSERT INTO (foo, bar, schoo) VALUES ("247", "AM PROV", "yyy")', 
    'INSERT INTO (foo, bar, schoo) VALUES ("279", "AM PENS", "zzz")', 
    'INSERT INTO (foo, bar, schoo) VALUES ("249", "AM PROV", "aaa")'
); */

var_dump($inserts);

编辑:虽然我认为您的 INSERT 语句中缺少表名。

Edit2:您可以像 Frosty Z 那样使用 array_keys 缩短代码并跳过第一个 foreach。

【讨论】:

【参考方案3】:
$inputArray = array('a' => array(1, 2, 3), 'b' => array("X'", 'Y', 'Z'));
$finalArray = array();

// build array with appropriate data rows

$finalIndex = 0;

foreach($inputArray as $key => $row)

  foreach($row as $value)
    $finalArray[$finalIndex][] = $value;

  $finalIndex++;


// format it as SQL insert queries

$fields = array_keys($inputArray);

foreach($finalArray as $row)

  echo "INSERT INTO table (".implode(", ", $fields).") "
    . " VALUES (".implode(", ", array_map("format_data", $row)).");\n";


function format_data($value)

  // assuming you're using MySQL. Replace the escape function by
  // the appropriate one
  if (is_string($value))
    return "'".mysql_real_escape_string($value)."'";
  else
    return $value;

【讨论】:

【参考方案4】:

您可以为此使用那些奇怪的 spl 迭代器之一 :)

$iter = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
foreach ($uberArray as $colName => $colValues) 
    $iter->attachIterator(new ArrayIterator($colValues), $colName);


foreach ($iter as $vals) 
    print_r($vals);
    //or $pdoStmt->execute($vals);

但实际上,一个简单的 for 循环是在这里使用的工具。

【讨论】:

【参考方案5】:

除非您想浪费内存,否则我认为没有理由合并数组。您可能已经制作了数据的副本。这只是逐行插入数据。

$data = array('foo' => array(...), ... );
$fields = array('foo', 'bar', 'schoo');
$c = count($data[$fields[0]));

$base_sql = 'INSERT INTO tbl ('.implode(',', $fields).') VALUES ';

for ($i = 0; $i < $c; ++$i)

  $row_data = array();
  foreach ($fields as $field)
     $row_data[] = "'".escape_func($data[$field][$i])."'";

  $sql = $base_sql . '(' . implode(',', $row_data). ')';
  db_query($sql);

我实际上会使用准备好的语句。

您真的应该尝试弄清楚如何一次性遍历原始数据集。

【讨论】:

我想这与@powerbuoy的回答基本相同,只是通过从主循环中拉出一些东西来稍微优化一下。

以上是关于动态合并数组的算法的主要内容,如果未能解决你的问题,请参考以下文章

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

使用动态键合并和求和对象数组

算法 - 合并两个有序数组成一个有序数组

算法 - 合并两个有序数组成一个有序数组

Python进行数组合并的方法

华为OD机试 - 合并数组(Python) | 机试题+算法思路+考点+代码解析 2023