Filtering posts from different categories into different section by doing WP_Query only once

As I said in the comments, if you want 5 (or a specific) number of posts per category, then you need to make multiple WP_Query calls. Otherwise, you could use something like new WP_Query( [ 'cat' => '1,2,3,4' ] ) and then group the returned posts by their category upon displaying the posts.

Working Examples

Revised so that categories without any posts do not get displayed. But see the note I put in Option 2 below.

Option 1: One WP_Query call with x posts per each category.

// Category IDs.
$cat_ids = [ 1, 2, 3, 4 ];

// For each category, query posts in that category, and just display them.
foreach ( $cat_ids as $id ) {
    $query = new WP_Query( [
        'cat'            => $id,
        'posts_per_page' => 5,
    ] );

    if ( $query->have_posts() ) {
        echo '<h2>' . esc_html( get_cat_name( $id ) ) . '</h2>';

        echo '<ul>';

        while ( $query->have_posts() ) {
            $query->the_post();

            echo '<li>';
            the_title( '<h3>', '</h3>' );
            // display other content you want
            echo '</li>';
        }

        echo '</ul>';
    }

    wp_reset_postdata();
}

Option 2: One WP_Query call for all the categories.

Note: With this option, there’s no guarantee that all the categories are always available on each page/request. But the point is, the grouping. I.e. You’d get the posts displayed under their own category.

// Category IDs.
$cat_ids = [ 1, 2, 3, 4 ];

// Get all posts that are assigned to any of the above categories.
$query = new WP_Query( [
    'cat'            => implode( ',', $cat_ids ),
    'posts_per_page' => 10,
] );

// And then when displaying the posts, group them under their own category.
foreach ( $cat_ids as $cat_id ) {
    $list="";

    if ( $query->have_posts() ) {
        while ( $query->have_posts() ) {
            $query->the_post();

            if ( has_category( $cat_id ) ) {
                $list .= '<li>';
                $list .= the_title( '<h3>', '</h3>', false );
                $list .= 'add other content you want here..';
                $list .= '</li>';
            }
        }
    }

    if ( $list ) {
        echo '<h2>' . esc_html( get_cat_name( $cat_id ) ) . '</h2>';
        echo '<ul>' . $list . '</ul>';
    }

    wp_reset_postdata();
}

I hope that helps, and just change the HTML to your liking.. Also, I’m assuming you’re referring to the default category taxonomy; but for other taxonomies, you’d use has_tag() or has_term() in place of has_category(), and (for example, you can use) get_term_field() for getting the term/tag name.