Q:

Shopify: Complicated variant display on collection pages

I’m setting up a custom Shopify theme for a client. Their products come in different colours and sizes. I need to display each colour variant separately on the collection page, but without showing all size variants as separate items.
Then, still on the collection page, within each product item, I need to display the range of sizes that variant is available in.
So something like:

T-shirt (Red)
Sizes: XS S M L XL XXL

T-shirt (Blue)
Sizes: XS S M L XL XXL

I’ve been using the solution from this post: Shopify show color variants in collection but not size variant, which has got me part of the way there - I am able to display the colour variants individually, but now I’m not sure how to then output the size variants along with the product.
Here’s a simplified version of the code I’m using:
{% for product in collection.products %}

    {% for option in product.options %}

        {% if option == "Color" or option == "Colour" %}

            {% assign index = forloop.index0 %}
            {% assign colorlist = '' %}
            {% assign color = '' %}

            {% for variant in product.variants %}

                {% capture color %}
                    {{ variant.options[index] }}
                {% endcapture %}

                {% unless colorlist contains color %}

                    {% assign product = variant %}

                    <a class="product" href="{{ product.url | within: collection }}">

                        <img src="{{ product.featured_image.src | img_url: '480x480' }}">

                        {{ product.title }}

                        <ul class="product__sizes">
                            <!-- Need to output sizes here -->
                        </ul>

                    </a>

                    {% capture tempList %}
                        {{colorlist | append: color | append: ' '}}
                    {% endcapture %}

                    {% assign colorlist = tempList %}

                {% endunless %}

            {% endfor %}

        {% endif %}

    {% endfor %}

{% endfor %}

Any help at all is much appreciated!

A:

You were almost there, but I had to clean your code a little since you had 3 for's in each other, which is quite a lot of loops.
Here is the modified code:
{% for product in collection.products %}
    {% assign options = product.options %}
    {% assign have_color = false %}
    {% assign size_index = false %}

    {% for option in options %}
        {% comment %}Check if there is a color option{% endcomment %}
        {% if option == "Color" or option == "Colour" %}
            {% assign have_color = forloop.index0 %}
        {% endif %}
        {% comment %}Get the size index{% endcomment %}
        {% if option == "Size" %}
            {% assign size_index = forloop.index0 %}
        {% endif %}
    {% endfor %}

    {% if have_color != false %}
        {% assign variants = product.variants %}
        {% assign colorlist = '' %}
        {% assign sizelist = '' %}
        {% assign color = '' %}

        {% comment %}Get All Sizes{% endcomment %}
        {% for variant in variants %}
            {% comment %}We use the @ to wrap the string since sizes tend to have parts of other sizes, example S,XS,L,XL,XXL{% endcomment %}
            {% assign string_check = variant.options[size_index] | append: '@' | prepend: '@' %}
            {% unless sizelist contains string_check %}
                {% capture sizelist %}{% unless forloop.first %}{{sizelist}},{% endunless %}@{{ variant.options[size_index] }}@{% endcapture %}
            {% endunless %}
        {% endfor %}

        {% assign sizelist_array = sizelist | replace: '@', '' | split: ',' %}

        {% for variant in variants %}
            {% capture color %}
                {{ variant.options[have_color] }}
            {% endcapture %}

            {% unless colorlist contains color %}

                {% assign product = variant %}

                <a class="product" href="{{ product.url | within: collection }}">

                    <img src="{{ product.featured_image.src | img_url: '480x480' }}">

                    {{ product.title }}
                    <ul class="product__sizes">
                      {% for size in sizelist_array %}
                        <li>
                            {{ size }}
                        </li>
                      {% endfor %}
                    </ul>

                </a>

                {% capture tempList %}
                  {{colorlist | append: color | append: ' '}}
                {% endcapture %}

                {% assign colorlist = tempList %}

            {% endunless %}

        {% endfor %}

    {% endif %}

{% endfor %}

The main difference is that I took out the color check in an outside for loop and in the same loop I get the size option index. In addition there is a separate loop that populate a sizelist variable. 
Here is a code breakdown of the additionally added items:
{% assign have_color = false %}
{% assign size_index = false %}

I added to variables, one for the color check and one for the size index.
{% for option in options %}
    {% comment %}Check if there is a color option{% endcomment %}
    {% if option == "Color" or option == "Colour" %}
        {% assign have_color = forloop.index0 %}
    {% endif %}
    {% comment %}Get the size index{% endcomment %}
    {% if option == "Size" %}
        {% assign size_index = forloop.index0 %}
    {% endif %}
{% endfor %}

In this loop we check if the product have a color and set the size index.
{% assign sizelist = '' %}

We create down another variables that will hold all of the sizes.
{% comment %}Get All Sizes{% endcomment %}
{% for variant in variants %}
    {% comment %}We use the @ to wrap the string since sizes tend to have parts of other sizes, example S,XS,L,XL,XXL{% endcomment %}
    {% assign string_check = variant.options[size_index] | append: '@' | prepend: '@' %}
    {% unless sizelist contains string_check %}
        {% capture sizelist %}{% unless forloop.first %}{{sizelist}},{% endunless %}@{{ variant.options[size_index] }}@{% endcapture %}
    {% endunless %}
{% endfor %}

Here we populate the sizelist variable with all the sizes, we use the @ character to create unique strings that we can check if they are contained in the list.
{% assign sizelist_array = sizelist | replace: '@', '' | split: ',' %}

After that we clean the populated variable from the @ character and split it by , to create an array.
<ul class="product__sizes">
    {% for size in sizelist_array %}
        <li>
            {{ size }}
        </li>
    {% endfor %}
</ul>

And this is the sweet moment when we output the sizes.

