How to group search results by post type and only if post type result is not empty?

The only way is to count them or (re)request them via WP_Query.
I think I prefer the first solution because it’s the less complex.

<?php if (have_posts()) : ?>
    <?php
    // We change the definition of the array to be able to store the count of each post_type
    $types = array('post' => 0, 'videos' => 0, 'graphics' => 0, 'photos' => 0);
    while (have_posts()) {
        the_post();
        // We check that only allowed post_type are counted
        if (array_key_exists(get_post_type(), $types)) {
            $types[get_post_type()]++;
        }
    }
    ?>
    <?php foreach ($types AS $type => $nb_of_type) : ?>
        <?php // We only show post_types that have at least one result  ?>
        <?php if ($nb_of_type > 0) : ?>
            <div class="card">
                <div class="card-header">
                    <h4><?= $type; ?></h4>
                </div>

                <div class="card-body">
                    <?php while (have_posts()) : the_post(); ?>
                        <?php if (get_post_type() === $type) : ?>
                            <?php get_template_part('template-part/content', $type); ?>
                        <?php endif; ?>
                    <?php endwhile; ?>
                </div>
            </div>
        <?php endif; ?>
    <?php endforeach; ?>
<?php endif; ?>