3

I've been going through the RxJS tutorials http://reactivex.io/learnrx/. Almost all of the exercises involve moving from a hierarchical structure to a flat structure so I thought I'd try to do the opposite.

I want to convert from a flat array to a tree structure based on a property of each array item, using the same functional constructs from the tutorial.

I.e. Go from this:

var videos = [
    {
        "id": 70111470,
        "title": "Die Hard",
        "category": "Action"
    },
    {
        "id": 654356453,
        "title": "Bad Boys",
        "category": "Action"
    },
    {
        "id": 65432445,
        "title": "Anchorman",
        "category": "Comedy"
    },
    {
        "id": 675465,
        "title": "Everest",
        "category": "New Release"
    }
];

To this (based on each video's category):

result === [
    {
        "category": "Action",
        "videos": [
            {
                "id": 70111470,
                "title": "Die Hard"
            },
            {
                "id": 654356453,
                "title": "Bad Boys"
            }
        ]
    },
    {
        "category": "Comedy",
        "videos": [
            {
                "id": 65432445,
                "title": "Anchorman"
            }
        ]
    },
    {
        "category": "New Release",
        "videos": [
            {
                "id": 675465,
                "title": "Everest"
            }
        ]
    }
];

I've come up with the following code that works, but I feel like I'm missing an easier way (perhaps solving in a single reduce) which would in turn be more performant (rather than filtering videos many times):

var result = 
    videos.reduce(function(catArray, video) {
       var catName = video.category;
       if (catArray.indexOf(catName) === -1) {
          catArray.push(catName);
       }
       return catArray;
    }, [])
    .map(function(categoryName) {
        return {
            category: categoryName,
            videos: videos.filter(function(video) {
                        return video.category === categoryName;
                    }).map(function(video) {
                        return {
                            id: video.id,
                            title: video.title
                        };
                    })
        };
    });

Is there a better way using functional methods?

1 Answer 1

3

This is simpler than a tree because your result can only have one level. All you want is to group your array by category and then map each group into objects. The map part will just be rearranging things a little bit into your final desired structure. You won't need to filter the full list of videos inside the map like you're currently doing.

Unfortunately, JavaScript isn't particularly friendly to the functional paradigm by default so it doesn't have a built in groupBy. So you can either reimplement grouping inside your reduce or you can use one from an external library like Ramda. The example code there should help you understand how groupBy works.

1
  • Fantastic, thanks very much for the link and your help! Jan 14, 2016 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.