Eleven11
Eleven11

Reputation: 95

Counting array items in object with regex

So I have an object:

   var data = {
      "movies": {
        "first": {
          "title": "Bruce Almigthy",
          "actors": ["Jim Carrey", "Morgan Freeman", "Jennifer Aniston"],
          "year": "2003"
        },
        "second": {
          "title": "The Truman Show",
          "actors": ["Jim Carrey", "Ed Harris","Morgan Freeman", "Laura Linney"],
          "year": "1998"
        },
        "third": {
          "title": "Ace Ventura",
          "actors": ["Jim Carrey", "Courteney Cox","Ed Harris"],
          "year": "1994"
        }
      }
    };

console.log(data.movies);

And I need to find actors that stared in 1+ movies, and actors that starred only in one movie. I usually handle this type of problem with something like this:

function countMax(data) { 

    var actors = {}; 

    Object.keys(data.movies).forEach(function (key) { 
        var movie = data.movies[key]; 

        movie.actors.forEach(function (actor) { 
            if (!actors.hasOwnProperty(actor)) actors[actor] = 0; 
            actors[actor]++;    
        }) 

    }) 

    Object.keys(actors).forEach(function (actor) { 

        var count = actors[actor]; 
        if (count > 1) console.log(actor + ' stars in ' + count + ' movies.'); 

    });

}; 

countMax(data);

I am wondering if there is a different way of doing this, maybe by using regex or something like that? I am just not sure how would I "approach" to the object.

Upvotes: 0

Views: 172

Answers (3)

user8897421
user8897421

Reputation:

I think I'd refactor it a bit.

var data = {"movies":{"first":{"title":"Bruce Almigthy","actors":["Jim Carrey","Morgan Freeman","Jennifer Aniston"],"year":"2003"},"second":{"title":"The Truman Show","actors":["Jim Carrey","Ed Harris","Morgan Freeman","Laura Linney"],"year":"1998"},"third":{"title":"Ace Ventura","actors":["Jim Carrey","Courteney Cox","Ed Harris"],"year":"1994"}}};

function countMax(data) {
  Array.from(Object.values(data.movies).reduce((m, movie) => {
    movie.actors.forEach(actor => m.set(actor, (m.get(actor) || 0) + 1));
    return m;
  }, new Map()).entries())
    .filter(([_, count]) => count > 1)
    .forEach(([actor, count]) => console.log(actor + ' stars in ' + count + ' movies.'))
}

countMax(data);

Upvotes: 0

Keith
Keith

Reputation: 24181

What you have done seems fine, regex is not a magic wand to solve all problems.

Here I've just modified what you have done using a bit more ES6 sugar. Like Object.values & Object.entries

ps. hasOwnProperty is not required, you needed it in ES5 when using for in, ps. for of can be used nowadays..

const data = {
  "movies": {
    "first": {
      "title": "Bruce Almigthy",
      "actors": ["Jim Carrey", "Morgan Freeman", "Jennifer Aniston"],
      "year": "2003"
    },
    "second": {
      "title": "The Truman Show",
      "actors": ["Jim Carrey", "Ed Harris","Morgan Freeman", "Laura Linney"],
      "year": "1998"
    },
    "third": {
      "title": "Ace Ventura",
      "actors": ["Jim Carrey", "Courteney Cox","Ed Harris"],
      "year": "1994"
    }
  }
};


function countMax(data) { 
  var actors = {}; 
  Object.values(data.movies).forEach(movie => 
    movie.actors.forEach(actor => actors[actor] = (actors[actor] | 0) + 1) 
  ) 
  Object.entries(actors).forEach(([actor, count]) => {
    if (count > 1) console.log(actor + ' stars in ' + count + ' movies.'); 
  });
}; 

countMax(data);

Upvotes: 0

Mark
Mark

Reputation: 92440

I don't think there's much a regex will do for you here, but you can shorten things a bit with some of the niceties of modern Javascript. For example you can make a map of the actors and counts with:

var actor_map = Object.values(data.movies).reduce((a, c) => {
    c.actors.forEach(i => a[i] = a[i] ? a[i]+1 : 1 )
    return a
}, {})

Then you can filter for the counts to get whatever you want:

var more_that_one = Object.entries(actor_map).filter(([k, v]) => v > 1)
var less_that_one = Object.entries(actor_map).filter(([k, v]) => v == 1)

var data = {
    "movies": {
      "first": {
        "title": "Bruce Almigthy",
        "actors": ["Jim Carrey", "Morgan Freeman", "Jennifer Aniston"],
        "year": "2003"
      },
      "second": {
        "title": "The Truman Show",
        "actors": ["Jim Carrey", "Ed Harris","Morgan Freeman", "Laura Linney"],
        "year": "1998"
      },
      "third": {
        "title": "Ace Ventura",
        "actors": ["Jim Carrey", "Courteney Cox","Ed Harris"],
        "year": "1994"
      }
    }
  };

var actor_map = Object.values(data.movies).reduce((a, c) => {
    c.actors.forEach(i => a[i] = a[i] ? a[i]+1 : 1 )
    return a
}, {})

var more_that_one = Object.entries(actor_map).filter(([k, v]) => v > 1)
var less_that_one = Object.entries(actor_map).filter(([k, v]) => v == 1)

console.log(more_that_one)
console.log(less_that_one)

Upvotes: 1

Related Questions