Loop through data file with "uniq" array filter

Hello, I'm trying to loop through a data file, and filter the output so that duplicate values of a field are removed. Any help? Many thanks in advance. Below is what I'm working with.

Data file:

- title: Heading 1
  source: Source 1

- title: Heading 1
  source: Source 2

- title: Heading 2
  source: Source 3

- title: Heading 2
  source: Source 4

HTML & Liquid:


    {% for item in site.data.elements %} {% assign my_filter = item.title | split: ' ' | uniq %}
  • {{ my_filter }}
  • {% endfor %}

Expected output:

  • Heading 1
  • Heading 2

I think you need to assign the array before you loop through the items. So maybe something like this?

<!-- get an array of the titles without dupes -->
{% capture filtered_titles_array %}{% for item in site.data.elements %}{{ item.title }}|{% endfor %}{% endcapture %}

<!-- start loop -->
{% for item in site.data.elements %}

    <!-- create a filter from the title -->
    {% assign filtered_title = item.title | append: '|' %}

    <!-- check the filter is in the title array -->
    {% if filtered_titles_array contains filtered_title %}
        <h2>{{ item.title }}</h2>
        <p>{{ item.source }}</p>
    {% endif %}

    <!-- remove title filter from the original array -->
    {% assign filtered_titles_array = filtered_titles_array | remove: filtered_title %}
{% endfor %}

This seems quite hacky, and I’m not even sure it’ll work. Let me know if it does. Anyone else who sees this could they check my math? Thanks

Edit: Turns out you don’t need to filter the array, the remove filter removes any instance of the string which is handy

Thanks very much, David! It works on my end. I don’t know enough to know whether it’s hacky. Let’s see if anyone else chimes in.

Another way to get this done is as follows:

{% assign titles = site.data.elements | map: 'title' | uniq %}

<ul>
  {% for item in titles %}
    <li>{{ item }}</li>
  {% endfor %}
</ul>

1 Like

This is far more elegant, thanks! I need to look into actually how map works :laughing:, I’ve used it in es6 code but not sure what it’s doing

map simply creates a new array of values of the named property (in the above example, title)

Ah I see, but surely this only filters out the duplicate titles? I think in @andrewlobo’s case they want to compare titles of the items and strip out the items which have duplicate titles. This would only loop through the titles

True, from Andrew’s “HTML-Liquid” Example and “Expected Output”, it looks like this is all he wants…

1 Like

Yep, filtering out duplicate titles was all I was trying to do. Sorry, @DavidDarnes , I wonder if adding a "source" field in the original post was overcomplicating the example. @ashmaroli, thanks very much for adding your method. I'd never be able to figure that out myself. Very grateful to both of you.

No problem! Might keep that example up just in case someone wants to achieve specifically that. Thanks for explaining @ashmaroli :+1:

Hello! Somebody found resolved?

I have array in JSON format

[
  {
      "id": 0,
      "type": "Type Zero",
      "date": "2020-02-22",
      "phone": 380001000000,
      "images":  ""
  },
  {
      "id": 1,
       "type": "Type One",
      "date": "2020-04-24",
      "phone": 380001000000,
      "images": ""
  },
  {
      "id": 2,
      "type": "Type Two",
      "date": "2020-07-08",
      "phone": 380002000000,
      "images": ""
  }
]

I only need to leave unique records. How to do it? for example by the field “phone” is it possible?

ashmaroli’s answer is correct:

For your array, I’m guessing it would look something like this (replace name-of-array with the name of your JSON file):

{% assign records = site.data.name-of-array | map: 'phone' | uniq %}

{% for item in records %}
  <div>{{ item }}</div>
{% endfor %}
1 Like

Thank you for the reply I know the way I saw him, but I do not receive that what I need…

I have the array in JSON format:

[
  {
      "id": 0,
      "type": "Type Zero",
      "date": "2020-02-22",
      "phone": 380001000000,
      "images":  ""
  },
  {
      "id": 1,
       "type": "Type One",
      "date": "2020-04-24",
      "phone": 380001000000,
      "images": ""
  },
  {
      "id": 2,
      "type": "Type Two",
      "date": "2020-07-08",
      "phone": 380002000000,
      "images": ""
  }
]

{%- assign model = site.data.models | map: "phone" | uniq -%}

I get: Liquid Exception: no implicit conversion of String into Integer in… hints at “phone”, but is not problem i changed it to…

[
  {
      "id": 0,
      "type": "Type Zero",
      "date": "2020-02-22",
      "phone": "380001000000",
      "images":  ""
  },
  {
      "id": 1,
       "type": "Type One",
      "date": "2020-04-24",
      "phone": "380001000000",
      "images": ""
  },
  {
      "id": 2,
      "type": "Type Two",
      "date": "2020-07-08",
      "phone": "380002000000",
      "images": ""
  }
]

{%- assign model = site.data.models | map: "phone" | uniq -%}

<ul>
  {%- for too in model -%}
  <li>{{ too.id }} / {{ too.type }} / {{ too.data }} / {{ too.phone }} / {{ too.images }}</li>
  {%- endfor -%}
</ul>

…in the array model i expected get

[
  {
      "id": 0,
      "type": "Type Zero",
      "date": "2020-02-22",
      "phone": "380001000000",
      "images":  ""
  },
  {
      "id": 2,
      "type": "Type Two",
      "date": "2020-07-08",
      "phone": "380002000000",
      "images": ""
  }
]
<ul>
  <li> 0 / Type Zero / 2020-02-22 / 380001000000 / </li>
  <li> 1 / Type Two / 2020-07-08 / 380002000000 / </li>
</ul>

but in the array model i get nothing if exactly I see

Now I see only one field “phone” i do not understand where other fields…?

<ul>
  <li> / / / 380001000000 / </li>
  <li> / / / 380002000000 / </li>
</ul>

Why? Did I miss something?

@typo3ua The answer I gave years ago was tailored for the question asked at the time. Your case is different and there isn’t a simple solution for it.

When the map filter is used, the result is a new array with just the values of the given attribute.
Therefore {{ site.data.models | map: "phone" }} will just result in the array [380001000000, 380001000000, 380002000000]. When this is passed onto the uniq filter, the resulting array would just be [380001000000, 380002000000].

1 Like

@ashmaroli thank you for the reply.
Yes! I am already understood. I used the example by @DavidDarnes and it works for me… I had hope for the bast solution, but at the moment his none…

1 Like