PHP数组解析

3

大家好,我有一个巨大的数组作为搜索结果返回,我想要做以下操作:

遍历数组,并为每个具有相同“spubid”的记录添加以下键/值:“sfirst,smi,slast”到父级数组成员中,在这种情况下为 $a [0]。因此,结果将保留 $a [0],但从数组中的其他成员中添加 sfirst、smi 和 slast 的值(因为它们都具有相同的“spubid”)。我认为将键值(1、2、3)添加到关联键(sfirst1 =>“J.”,smi1 =>“F.”,slast1 =>“Kennedy”)会很好。然后,我想删除该“spubid”下其余的数组成员(使用 unset())。以下是我收到的数组的简化示例,在此示例中,所有记录都具有相同的“spubid”:

Array ( 
  [0] => 
    Array ( 
      [spubid] => A00502 
      [sfirst] => J. 
      [smi] => A. 
      [slast] => Doe
  [1] => 
    Array ( 
      [spubid] => A00502 
      [sfirst] => J. 
      [smi] => F. 
      [slast] => Kennedy 
  [2] => 
    Array ( 
      [spubid] => A00502 
      [sfirst] => B. 
      [smi] => F. 
      [slast] => James 
  [3] => 
    Array ( 
      [spubid] => A00502
      [sfirst] => S. 
      [smi] => M. 
      [slast] => Williamson 
      )
    )

实质上,我想保留 $a[0],但向其添加新的键=>值 (sfirst$key, smi$key, slast$key),并将具有相同 "spubid" 的所有成员的 "sfirst、smi、slast" 值附加到其中,然后取消设置 $a[1]-[3]。

只是为了澄清我的理想最终结果应该是:

Array ( 
  [0] => 
    Array ( 
      [spubid] => A00502 
      [sfirst] => J. 
      [smi] => A. 
      [slast] => Doe
      [sfirst1] => J.
      [smi1] => F. 
      [slast1] => Kennedy
      [sfirst2] => B. 
      [smi2] => F. 
      [slast2] => James 
      [sfirst3] => S. 
      [smi3] => M. 
      [slast3] => Williamson
    )
  )

在大多数情况下,我会有一个更大的数组来开始处理,其中包含许多“spubid”,但99%的出版物都有多个作者,因此这个例程非常有用,可以清理结果并使解析过程更容易显示。
***更新
我认为通过简化我的示例可能会使事情不清楚。我喜欢Chacha102和zombat的回答,但我的“父数组”包含了更多的数据,那只是主键而已。我需要保留来自该记录的许多其他数据,其中小部分如下:
[spubid] => A00680 
[bactive] => t 
[bbatch_import] => t 
[bincomplete] => t 
[scitation_vis] => I,X 
[dentered] => 2009-08-03 12:34:14.82103 
[sentered_by] => pubs_batchadd.php 
[drev] => 2009-08-03 12:34:14.82103 
[srev_by] => pubs_batchadd.php 
[bpeer_reviewed] => t 
[sarticle] => A case study of bora-driven flow and density changes on the Adriatic shelf (January 1987)
.
.
.
.
.

每次搜索查询大约会返回40个列。不要像这些示例中使用pubid一样硬编码它们,如何在仍然进行您们两位建议的更改的同时包含它们呢?创建一个多维数组(正如你们两位建议的那样),并将作者作为多维数组的一部分是完全可以的,感谢你们两位的建议。
****更新:
这是我找到的解决方案,非常简单,而且很好地完成了工作。最终我确实创建了一个多维数组,所以作者也被分开了。
过于简化的解决方案:
$apubs_final = array();
$spubid = NULL;
$ipub = 0;

foreach($apubs as $arec)
{
  if($spubid != $arec['spubid'])
  {
    $ipub++;
    $apubs_final[$ipub] = $arec;
    // insert UNSET statements here for author data
    $iauthor = 0;
    $spubid = $arec['spubid'];
  }
  $iauthor++;
  $apubs_final[$ipub]['authors'][$iauthor]['sauthor_first'] = $arec['sfirst'];
} 

感谢所有回复的人,非常感谢你们的帮助!


获取一个作者数组的数组,每个数组包含sfirst、smi和slast,这样会更容易吗? - Tyler Carter
我在我的答案中为您两种方式都做了,以防您愿意切换到不同的格式。 - Tyler Carter
你对最终得到的数组要做什么?为什么它需要以那种格式呈现? - rojoca
匈牙利命名法让我眼睛流血。 - jason
rojoca:我建议的格式很容易解析,就像$a['spubid']['authors'][sfirst]这样的格式...我只需要将完整的作者列表与单个pubid关联起来。结果是从嵌套的SQL JOIN返回的,因此产生了大量的数据。 - niczak
显示剩余2条评论
4个回答

3
// First, probably the more parsable way.
foreach($array as $key => $values)
{
    $end[$spuid] = $values;
    $spuid = $values['spuid']
    $end[$spuid]['authors'][] = array('sfirst' => $values['sfirst'],
                          'smi' => $values['smi'],
                           'slast' => $values['slast']);

}

将会得到这样的一个数组

Array(
    [A00502] =>
         Array(
           [supid] => A00502
               .... other values .....
           [authors] =>
                 Array(
                [0]=>
                      Array(
                    ['sfirst'] => '',
                    ['smi'] => '',
                    ['slast'] => '')
                )
        )
)

如果你计划在页面上显示该内容,我认为使用数组会更易于解析,因为你可以对作者进行foreach循环,这是我看到许多人在处理此类属性时的做法。

如果你真的想要你理想中的格式,请在之后使用此方法。

$count = 0;
foreach ($end as $supid => $values)
{
    $other_end[$count] = $values;
    $other_end[$count]['spuid'] = $spuid;
    foreach($values['authors'] as $key => $author)
    {
        if($key == 0)
        {
            $suffix = '';
        }
        else
        {
            $suffix = $key;
        }
        $other_end[$count]['sfirst'.$suffix] = $author['sfirst'];
        $other_end[$count]['smi'.$suffix] = $author['smi'];
        $other_end[$count]['slast'.$suffix] = $author['slast'];
    }

}

非常好的解决方案,我编辑了原始帖子,因为我稍微过于简化事物,从而使我的总体问题不明确。我很抱歉! - niczak
更新了,它非常相似,你可能会有一些额外的键,但所有内容都在那里。 - Tyler Carter
基本上,您将拥有数组中最后一个人的额外的名字、中间名和姓,但这不应该对其产生太大影响。 - Tyler Carter
你更新的解决方案让我达到了我需要的目标,我编辑了原帖并附上了我采用的解决方案。再次非常感谢你的帮助。 - niczak
你知道每个回答者都在等待看你选择哪个回答作为被采纳的答案。 :P - Tyler Carter
与我最终采用的方法非常相似,您的方法给了我灵感,使我到达了目标。再次感谢 Chacha102。我的解决方案已在第二次编辑中添加到原始帖子中。 - niczak

2
为什么不创建一个以spubid为键的数组:
// assuming $array is your array:

$storage = array();
foreach($array as $entry) {
  $bid = $entry['spubid'];
  if (!isset($storage[$bid])) {
    // duplicate entry - taking the author out of it.
    $stortmp = $entry;
    unset($stortmp['sfirst'], $stortmp['smi'], $stortmp['slast']);
    // add an authors array
    $stortmp['authors'] = array();
    $storage[$bid] = $stortmp;
  }
  $author = array(
    'sfirst' => $entry['sfirst'], 
    'smi' => $entry['smi'], 
    'slast' => $entry['slast']);
  $storage[$bid]['authors'][] = $author;
}

现在你的$storage数组应该是这样的:
Array(
  "A00502" => Array(
    "spubid" => "A00502",
    "authors" => Array(
      [0] => 
        Array ( 
          [sfirst] => J. 
          [smi] => A. 
          [slast] => Doe
       [1] => 
         Array ( 
          [sfirst] => J. 
          [smi] => F. 
          [slast] => Kennedy

您可以轻松对作者进行foreach迭代并打印它们:

foreach ($storage as $pub) {
  echo 'Pub ID: '.$pub['spubid']."<br/>";
  foreach ($pub['authors'] as $author) {
    echo 'Author: '.$author['sfirst'].' '.$author['smi'].' '.$author['slast']."<br/>";
  }
}

作为额外的奖励,您可以访问$storage['A00502']

更新评论

看起来您的数组可能来自涉及从出版物表到作者表的JOIN的某种SQL查询。这使得结果数据集重复了很多不真正需要的信息。没有理由让所有出版物数据多次传输/检索数据库。尝试重新编写它以获取将要显示的所有书籍的查询,然后进行“作者”查询,例如:

SELECT * FROM authors WHERE spubid IN ('A00502', 'A00503', 'A00504');

然后将其转换为此数组以用于显示目的。这将有助于降低您的数据库流量水平。

这并没有按预期工作,我仍然携带着所有重复的数据。我的原始帖子中我过于简化了示例,这肯定是误导性的。因此,我已经扩展了这个示例。 - niczak
我已编辑示例以向您展示如何保留所有数据,但这让我想到您的问题更多是关于数据集的问题。答案末尾有关于数据集的部分。 - gnarf
这实际上是我的初始方法,使用一个查询获取所有的pub信息,然后再用另一个查询获取作者。个人更喜欢这种方法,因为你只查询需要的数据。然而,权力机构告诉我不能使用这种方法,需要使用单个查询完成所有操作。因此,需要使用嵌套连接... - niczak

1

这段代码应该按照您的要求正常工作。我采用了使用一些临时数组的方法来进行主数组键和spubid子键之间的相关性。

/* assume $array is the main array */
$array = array(
    array('spubid' => 'A00502','sfirst'=>'J.','smi'=>'A.','slast'=>'Doe'),
    array('spubid' => 'A00502','sfirst'=>'J.','smi'=>'F.','slast'=>'Kennedy'),
    array('spubid' => 'A00502','sfirst'=>'B.','smi'=>'F.','slast'=>'James'),
    array('spubid' => 'BXXXXX','sfirst'=>'B.','smi'=>'F.','slast'=>'James'),
    array('spubid' => 'A00502','sfirst'=>'S.','smi'=>'M.','slast'=>'Williamson')
);

//track spubid positions in the main array
$keyPositions = array();
//keys to delete after array iteration
$keyDel = array();
//track how many spubkey increments you've made to the fields
$spubKeys = array();
//fields to copy between spubids
$copyFields = array('sfirst','smi','slast');

foreach($array as $key => $subarr)
{
    if (isset($subarr['spubid'])) {
        if (isset($keyPositions[$subarr['spubid']])) {
            //spubid already exists at a main array key, do the copy
            $spubKey = ++$spubKeys[$subarr['spubid']];
            foreach($copyFields as $f) {
                $array[$keyPositions[$subarr['spubid']]][$f.$spubKey] = $subarr[$f];
            }
            $keyDel[] = $key;
        }
        else {
            //First time encountering this spubid, mark the position
            $keyPositions[$subarr['spubid']] = $key;
            $spubKeys[$subarr['spubid']] = 0;
        }
    }
}
if (count($keyDel)) {
    foreach($keyDel as $idx) unset($array[$idx]);
}

var_dump($array);

由于对问题中的某些数据进行了过度简化,我编辑了原始帖子。你能再看一下吗?非常感谢你提供的出色解决方案。 - niczak

0
为了避免跟踪将组数据推入结果数组的位置,可以分配引用。同时,还要维护一个计数器变量,以确定是否以及应该将整数附加到随后遇到的数据集的键上。
代码:(演示)
$result = [];
foreach ($array as $row) {
    $id = $row['spubid'];
    if (!isset($ref[$id])) {
        $ref[$id] = $row;
        $counter[$id] = 0;
        $result[] = &$ref[$id];  // push group reference into result array
    } else {
        unset($row['spubid']);
        ++$counter[$id];
        foreach ($row as $k => $v) {
            $ref[$id][$k . $counter[$id]] = $v; // push assoc elements into group reference
        }
    }
}
var_export($result);

就我个人而言,我认为这是一个XY问题——你可能不应该使用数字来表示子组。在专业应用中,我会使用更深层次的子数组(每个组)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接