如何在 PHP 中将此 MN mysql 数组转换为另一个数组? (里面有例子)

发布于 2024-12-24 01:08:34 字数 736 浏览 2 评论 0原文

好吧,在 mysql 的关系 MN 中获得这样的数组是很常见的:

[0]
'book_id' => 1
'title' => 'title'
'author_id' => 1
'author_name' => 'name1'

[1]
'book_id' => 1
'title' => 'title'
'author_id' => 2
'author_name' => 'name2'

那么,有一种优雅/简单的方法来转换这种类型或类似的数组吗?

'book_id' => 1
'title' => 'title'
'authors' => array( 0 => array( 'author_id' => 1, 'author_name' => 'name1' ),
1 => array( 'author_id' => 2, 'author_name' => 'name2' ) )

我没有找到任何脚本或函数组合来实现这个...并且很常见,也许我没有正确搜索..不知道如何调用问题...

有什么想法或经验吗?

谢谢:)

PS:我不想在 MySQL 中使用 GROUP BY + GROUP CONCACT,我发现这个解决方案非常丑陋......

编辑: 我正在做一些通用的事情,不仅仅是为了解决这个特定的问题..

Well, is pretty common to get an array like this in relations M-N in mysql:

[0]
'book_id' => 1
'title' => 'title'
'author_id' => 1
'author_name' => 'name1'

[1]
'book_id' => 1
'title' => 'title'
'author_id' => 2
'author_name' => 'name2'

So, there is an elegant/easy way to convert this kind or arrays in something like this?

'book_id' => 1
'title' => 'title'
'authors' => array( 0 => array( 'author_id' => 1, 'author_name' => 'name1' ),
1 => array( 'author_id' => 2, 'author_name' => 'name2' ) )

I don't find any script or combinations of functions that made this... and is pretty common, maybe I have not searched correctly.. don't know how to call the problem...

Any ideas or experiences?

Thanks :)

PS: I don't want to use GROUP BY + GROUP CONCACT in MySQL, I found that pretty ugly solution...

EDIT:
I'm working in something generic, not only to solve this specific problem..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

回梦 2024-12-31 01:08:34

我会在 SQL 中执行 JOIN 操作,然后将结果后处理到 PHP 代码中的嵌套数组中。

$bookkeys = array_flip(array("book_id", "title"));
$authorkeys = array_flip(array("author_id", "author_name"));

$stmt = $dbh->query("...");

$books = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  if (!array_key_exists($row["book_id"], $books)) {
    $books[ $row["book_id"] ] = array_intersect_key($row, $bookkeys);
  }
  $books[ $row["book_id"] ]["authors"][] = array_intersect_key($row, $authorkeys);
}

如果您希望最终的数组是一个序数数组而不是由 book_id 作为键,您可以将其转换:

$books = array_values($books);

I would do the JOIN in SQL and the post-process the results into a nested array in PHP code.

$bookkeys = array_flip(array("book_id", "title"));
$authorkeys = array_flip(array("author_id", "author_name"));

$stmt = $dbh->query("...");

$books = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  if (!array_key_exists($row["book_id"], $books)) {
    $books[ $row["book_id"] ] = array_intersect_key($row, $bookkeys);
  }
  $books[ $row["book_id"] ]["authors"][] = array_intersect_key($row, $authorkeys);
}

If you want the final array to be an ordinal array instead of keyed by book_id, you can convert it:

$books = array_values($books);
不必了 2024-12-31 01:08:34

多个子键的通用解决方案:

$rows = collapse_rows($rows, 'book_id', array(
        'author_id' => array('author_name'),
    ));

function collapse_rows($rows, $key, $subkeys){

    # make a map of all fields we don't perform a simple copy on
    $skip_fields = array();
    foreach ($subkeys as $k => $v){
        $skip_fields[$k] = 1;
        foreach ($v as $v2) $skip_fields[$v2] = 1;
    }

    # now build our output
    $out = array();
    foreach ($rows as $row){
        $row2 =& $out[$row[$key]];

        # simple fields first
        foreach ($row as $k => $v){
            if (!$skip_fields[$k])){
                $row2[$k] = $v;
            }
        }

        # now subkeys
        foreach ($subkeys as $k => $v){
            $sub_row = array($k => $row[$k]);
            foreach ($v as $v2) $sub_row[$v2] = $row[$v2];
            $row2[$k][$sub_row[$k]] = $sub_row;
        }
    }

    return $out;
}

这使您可以传递主键以及子键和字段的哈希值以进行聚合。

A generic solution for multiple sub-keys:

$rows = collapse_rows($rows, 'book_id', array(
        'author_id' => array('author_name'),
    ));

function collapse_rows($rows, $key, $subkeys){

    # make a map of all fields we don't perform a simple copy on
    $skip_fields = array();
    foreach ($subkeys as $k => $v){
        $skip_fields[$k] = 1;
        foreach ($v as $v2) $skip_fields[$v2] = 1;
    }

    # now build our output
    $out = array();
    foreach ($rows as $row){
        $row2 =& $out[$row[$key]];

        # simple fields first
        foreach ($row as $k => $v){
            if (!$skip_fields[$k])){
                $row2[$k] = $v;
            }
        }

        # now subkeys
        foreach ($subkeys as $k => $v){
            $sub_row = array($k => $row[$k]);
            foreach ($v as $v2) $sub_row[$v2] = $row[$v2];
            $row2[$k][$sub_row[$k]] = $sub_row;
        }
    }

    return $out;
}

This lets you pass the primary key and a hash of sub keys and fields to aggregate by.

家住魔仙堡 2024-12-31 01:08:34

好吧,我有一个基于 Bill Karwin 建议的“解决方案”:

$key    = 'authors';
$output = array();
if ( is_array( $elements ) )
{
    $all_keys           = array_keys( $elements[0] );
    $conflicted_keys    = call_user_func_array( 'array_diff_assoc', $elements );
    $conflicted_keys    = array_keys( $conflicted_keys );
    $good_keys          = array_diff( $all_keys, $conflicted_keys );

    $conflicted_keys_fliped     = array_flip( $conflicted_keys );
    $good_keys_fliped           = array_flip( $good_keys );

    foreach ( $elements as $row )
    {
        if ( !array_key_exists( $row[$good_keys[0]], $output ) ) {
            $output[ $row[$good_keys[0]] ]          = array_intersect_key($row, $good_keys_fliped);
        }
        $output[ $row[$good_keys[0]] ][ $key ][]    = array_intersect_key( $row, $conflicted_keys_fliped );
    }
}

$output     = array_values($output);
var_dump($output);

不知道是否是最有效/最正确的。另一方面,如果存在不止一种类型的冲突,这将不起作用...补丁将是好评:)

谢谢大家!

Well, I have a "solution" based in Bill Karwin suggestion:

$key    = 'authors';
$output = array();
if ( is_array( $elements ) )
{
    $all_keys           = array_keys( $elements[0] );
    $conflicted_keys    = call_user_func_array( 'array_diff_assoc', $elements );
    $conflicted_keys    = array_keys( $conflicted_keys );
    $good_keys          = array_diff( $all_keys, $conflicted_keys );

    $conflicted_keys_fliped     = array_flip( $conflicted_keys );
    $good_keys_fliped           = array_flip( $good_keys );

    foreach ( $elements as $row )
    {
        if ( !array_key_exists( $row[$good_keys[0]], $output ) ) {
            $output[ $row[$good_keys[0]] ]          = array_intersect_key($row, $good_keys_fliped);
        }
        $output[ $row[$good_keys[0]] ][ $key ][]    = array_intersect_key( $row, $conflicted_keys_fliped );
    }
}

$output     = array_values($output);
var_dump($output);

Don't know if is the most eficient/correct.. On other hand, this will not work if there are more than one type of conflict... patches will be good received :)

thanks to all!

╰◇生如夏花灿烂 2024-12-31 01:08:34

像这样简单的东西就可以工作:

$out = array();
foreach ($rows as $row){
    $out[$row['book_id']]['book_id'] = $row['book_id'];
    $out[$row['book_id']]['title'] = $row['title'];
    $out[$row['book_id']]['authors'][$row['author_id']] = array(
        'author_id' => $row['author_id'],
        'author_name'   => $row['author_name'],
    );
}

行由书籍 ID 和作者 ID 键入,因此每本书只有一个输出行,然后该行中的每个作者都有一个输出行。

Something simple like this would work:

$out = array();
foreach ($rows as $row){
    $out[$row['book_id']]['book_id'] = $row['book_id'];
    $out[$row['book_id']]['title'] = $row['title'];
    $out[$row['book_id']]['authors'][$row['author_id']] = array(
        'author_id' => $row['author_id'],
        'author_name'   => $row['author_name'],
    );
}

Rows are keyed by book ID and then author ID so we only have one output row per book and then per author inside that row.

贱人配狗天长地久 2024-12-31 01:08:34

好吧,这是我最终将使用的函数,它完全基于 Cal 的想法,但尝试使用本机函数,如 Bill Karvin 所说:

protected function collapse_rows( $rows, $key, $subkeys ) {
if ( is_array( $rows ) )
{
    // make a map of all fields we don't perform a simple copy on
    $skip_fields = array();
    foreach( $subkeys as $sub ) {
        $skip_fields = array_merge( $skip_fields, array_reverse( $sub ) );
    }        
    $skip_fields = array_flip( $skip_fields );

    // now build our output
    $out = array();
    foreach ( $rows as $row ) {

        // simple fields first
        if ( !array_key_exists( $row[$key], $out ) ) {
            $out[ $row[$key] ]  = array_diff_key( $row, $skip_fields );
        }

        // now subkeys
        foreach ( $subkeys as $k => $v ) {
            $value      = array_intersect_key( $row, array_flip( $subkeys[$k] ) );
            if ( !empty( $value ) ) {
                $out[ $row[$key] ][ $k ][]  = $value;   
            }
        } 
    }

    return array_values( $out );
}
return $rows;

}

一旦完成,我认为它不会有太多好的性能。 .我想知道其他人如何解决此类问题...

无论如何,感谢两者!

Well, this is the funcion that finally I will use, it is based completly in the idea of Cal but trying to use native functions as said Bill Karvin:

protected function collapse_rows( $rows, $key, $subkeys ) {
if ( is_array( $rows ) )
{
    // make a map of all fields we don't perform a simple copy on
    $skip_fields = array();
    foreach( $subkeys as $sub ) {
        $skip_fields = array_merge( $skip_fields, array_reverse( $sub ) );
    }        
    $skip_fields = array_flip( $skip_fields );

    // now build our output
    $out = array();
    foreach ( $rows as $row ) {

        // simple fields first
        if ( !array_key_exists( $row[$key], $out ) ) {
            $out[ $row[$key] ]  = array_diff_key( $row, $skip_fields );
        }

        // now subkeys
        foreach ( $subkeys as $k => $v ) {
            $value      = array_intersect_key( $row, array_flip( $subkeys[$k] ) );
            if ( !empty( $value ) ) {
                $out[ $row[$key] ][ $k ][]  = $value;   
            }
        } 
    }

    return array_values( $out );
}
return $rows;

}

Once done, I don't think it has a too much good performance... I wonder how other people solve this kind of problems...

Whatever, thanks to both!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文