Find unique values from an array in React/js
Asked Answered
D

5

7

I'm a beginner in JavaScript and an even bigger beginner in ReactJS. Most of the following I've taken from tutorials and am trying to adapt it. So the codes displays all the values from the "tag" (people, places, places, etc.). It displays it as inline li elements as it's going to be a menu. The problem is that it displays all the tag for all the elements. I just want it to catch the unique 'tag' values for the menu (eg. people, places, things,...). I've tried _.uniq but it did not display the array. Thank you.

import React from "react";
import GalleryHeader from './GalleryHeader';
import ImageEntry from './ImageEntry';
import _ from 'lodash';

export default class GalleryImages extends React.Component {

    renderItems() {
        return _.map(this.props.images, (image, index) => <ImageEntry key={index} {...image} />);
    }

  renderMenu() {
    return _.map(this.props.images, (image, index) => <GalleryHeader key={index} {...image} />);
  }


  render() {

    return (
      <div>
      <ul class="list-inline">
        {this.renderMenu()}
      </ul>
        {this.renderItems()}          
      </div>
    );
  }
}

GalleryHeader

import React from "react";


export default class GalleryHeader extends React.Component {

  render() {

    return (
            <li>{this.props.tag}</li>
    );
  }
}

Images are stored in:

Gallery

import React from "react";

import GalleryImages from './Gallery/GalleryImages';


var images = [{
  "id": 1,
  "tag": "people",
  "src": "img/img1.jpg",
  "bsrc": "img/img1b.jpg",
  "alt": "Some description"
}, {
  "id": 2,
  "tag": "places",
  "src": "img/img2.jpg",
  "bsrc": "img/img2b.jpg",
  "alt": "Some description"
}, {
  "id": 3,
  "tag": "places",
  "src": "img/img3.jpg",
  "bsrc": "img/img3b.jpg",
  "alt": "Some place description"
}, {
  "id": 4,
  "tag": "things",
  "src": "img/img4.jpg",
  "bsrc": "img/img4b.jpg",
  "alt": "Internet of things"
}, {
  "id": 5,
  "tag": "people",
  "src": "img/img5.jpg",
  "bsrc": "img/img5b.jpg",
  "alt": "A personal person"
}, {
  "id": 6,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 7,
  "tag": "people",
  "src": "img/img7.jpg",
  "bsrc": "img/img7b.jpg",
  "alt": "Tarabaora"
}, {
  "id": 8,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 9,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}];

export default class Gallery extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      images,
      people: _.filter(images, {tag: "things"}),    // or in ES6 just people
      sources: _.filter(images, {tag: "src"}),
      places: _.filter(images, {tag: "places"}),
      cats: _.uniq(images)
    };
  }

  render() {
    // This is how you can filter them
    var ima = _.filter(images, {tag: "things"});
    console.log(ima);


    return (
      <div className="koko">
        <h1>This isGalleryfemCount</h1>
        <GalleryImages images={this.state.images} />
      </div>
    );
  }
}
Dott answered 13/3, 2016 at 21:36 Comment(0)
R
12

As I understand, you want to filter out original image collection by given tag. Correct?
If so, create filter function, which accepts tag and collection to filter. You can reuse this function then.

var images = [{
  "id": 1,
  "tag": "people",
  "src": "img/img1.jpg",
  "bsrc": "img/img1b.jpg",
  "alt": "Some description"
}, {
  "id": 2,
  "tag": "places",
  "src": "img/img2.jpg",
  "bsrc": "img/img2b.jpg",
  "alt": "Some description"
}, {
  "id": 3,
  "tag": "places",
  "src": "img/img3.jpg",
  "bsrc": "img/img3b.jpg",
  "alt": "Some place description"
}, {
  "id": 4,
  "tag": "things",
  "src": "img/img4.jpg",
  "bsrc": "img/img4b.jpg",
  "alt": "Internet of things"
}, {
  "id": 5,
  "tag": "people",
  "src": "img/img5.jpg",
  "bsrc": "img/img5b.jpg",
  "alt": "A personal person"
}, {
  "id": 6,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 7,
  "tag": "people",
  "src": "img/img7.jpg",
  "bsrc": "img/img7b.jpg",
  "alt": "Tarabaora"
}, {
  "id": 8,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 9,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}];

const filter = (tag, arr) => arr.filter(img => img.tag === tag);

// or in ES5
// var filter = function(tag, arr) {
//    return arr.filter(function(img) {
//        return img.tag === tag;
//    })
// };

const filtered = filter('people', images);

Edit
Added code to pick all unique tag names. Dependency free. Unline Set, this works in IE < 11.

const uniqueTags = [];
images.map(img => {
    if (uniqueTags.indexOf(img.tag) === -1) {
        uniqueTags.push(img.tag)
    }
});
Rhinencephalon answered 13/3, 2016 at 21:47 Comment(8)
Thank you. You've preemptied my next question. That's exactly what I'm trying to do and your answer will come handy. At the moment, I'm stuck one step before that. Trying to generate a menu that should be: places, people, things. My code above generates: people, places, places, things, people, places, people, places, etc.)Dott
Edited my response. Added code that extracts unique tag names.Rhinencephalon
Hi Andrey. I wonder if you could answer one more question on my code. In the renderItems function, do I need the 'index' argument in (images, index) and the subsequent "key={index}? What is the index for? It seems to work without. Thank youDott
Technically, you don't need it. On the other hand React asks you to provide key prop when rendering array if items for internal optimisations. Actually, it's better to avoid passing index as key, instead unique value should be passed. In your case, you may use key={image.id}, since it's unique. In situations when you cannot assign unique value, feel free to use index (when there is no better option)Rhinencephalon
Ok, I see. Thank you.Dott
I'm getting an error: I did (image, image.id) => blah blah key={image.id} blah. It does not seem to like the first image.idDott
_.map(this.props.images, (image) => <ImageEntry key={image.id} {...image} />)Rhinencephalon
Brilliant use of the map. Thanks for updating this.Wistful
S
4

It is similar The SQL SELECT DISTINCT Statement in javascript

const uniqueTags = [];
images.map((item) => {
  var findItem = uniqueTags.find((x) => x.tag === item.tag);
  if (!findItem) uniqueTags.push(item);
});
Spinozism answered 9/9, 2020 at 9:16 Comment(0)
D
3

Typescript sets source

For those who are using Typescripts I would recomend TypeScript Set

Array.from(new Set(yourArray.map((item: any) => item.id)))
Duiker answered 1/2, 2021 at 14:30 Comment(0)
P
1

Since they are plain strings you can create a JavaScript Set for that.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

Palpitation answered 13/3, 2016 at 21:40 Comment(3)
Will not work, since each object in collection (array) is different object (references are different).Rhinencephalon
But he want only the 'tag' value of each elements to build a menu. He can create a set with each tag string. No?Palpitation
Then yes. Unfortunately, you need flatten array (given in example) and then create Set from such array const tags = new Set(images.map(img => img.tag)); Unfortunately, we need to support old IE. Without this, I would definitely go with Set as you suggest :)Rhinencephalon
Z
0

As stated in this documentation[1] we can use the uniqBy method to return the unique element in an object array. Please refer the below code.

import _ from 'lodash';
_.uniqBy([{ 'id': 100 }, { 'id': 200 }, { 'id': 300 },{ 'id': 100 }], 'id');

This will return an output like this [{ 'id': 100 }, { 'id': 200 }, { 'id': 300 }]

[1] https://lodash.com/docs/#uniqBy

Zlatoust answered 25/1, 2021 at 5:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.