1

So I have this data, which contains an array of objects, the objects are blogs info, and they have authors, title, likes, link, etc.

What I wan't to do is get the author with the most likes across this array of data.

   const blogs = [ { _id: "5a422a851b54a676234d17f7", title: "React patterns", author: "Michael Chan", url: "https://reactpatterns.com/", __v: 0 }, { _id: "5a422aa71b54a676234d17f8", title: "Go To Statement Considered Harmful", author: "Edsger W. Dijkstra", url: "http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html", likes: null, __v: 0 }, { _id: "5a422b3a1b54a676234d17f9", title: "Canonical string reduction", author: "Edsger W. Dijkstra", url: "http://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD808.html", likes: 12, __v: 0 }, { _id: "5a422b891b54a676234d17fa", title: "First class tests", author: "Robert C. Martin", url: "http://blog.cleancoder.com/uncle-bob/2017/05/05/TestDefinitions.htmll", likes: 10, __v: 0 }, { _id: "5a422ba71b54a676234d17fb", title: "TDD harms architecture", author: "Robert C. Martin", url: "http://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html", likes: 0, __v: 0 }, { _id: "5a422bc61b54a676234d17fc", title: "Type wars", author: "Robert C. Martin", url: "http://blog.cleancoder.com/uncle-bob/2016/05/01/TypeWars.html", likes: 2, __v: 0 }

for example:

getAuthorWithMostLikes(blogs)

And it would check the array, sum the number of likes for every author across every article and return for example:

{author: Robert C. Martin, totalLikes: 12}

How can I achieve this in a clean way? I already "solved" it but I think the code is pretty messy and not readable

Here's my code:

const likesByAuthor = (blogs) =>{
    const blogsWhereThereIsAnAuthor = blogs.filter(blog=> blog.author)
    console.log("length of filtered array", blogsWhereThereIsAnAuthor.length)
    let authorsAndLikes = []
    let contin = undefined;
    blogsWhereThereIsAnAuthor.forEach((blog, index) => {
        let author = blog.author;
        let likes = blog.likes;
        // initialize concentrado
        console.log("loop for: ", author)
        if (!likes){
            return false
        }
        if (authorsAndLikes.length < 1){
            authorsAndLikes.push({author, likes})
            console.log("initial data", authorsAndLikes)
            return
        }

        authorsAndLikes.forEach((item) => {
            console.log(item.author, "|", blog.author, item.author === blog.author)
            if (item.author === blog.author) {
                console.log("case 1: existing author", item.author, "|", blog.author)
                console.log(item)
                item.likes += blog.likes;
                console.log(item)
                console.log(authorsAndLikes)
                contin = false;
                return false;
            }
            contin = true;

        })
        if (contin !== false) {
            console.log("case 2: new author, adding it to concentrado array", blog.author)
            authorsAndLikes.push({"author": author, "likes": likes})
            console.log(authorsAndLikes)
            console.log("end of iteration case 2")
        }
    })

    return authorsAndLikes;
}

const mostLikes = (blogs) =>{
    const likesCountByAuthor = likesByAuthor(blogs)
    return likesCountByAuthor.reduce((curr, sum) => curr.likes > sum.likes ? curr : sum)
}

How can I achieve the same result with more clean code or in a more efficient way?

1 Answer 1

2

One way to do this a little more cleanly is to create a single object like this:

{
   author: likes
}

instead of a list of objects. If you want the list instead, this object can be morphed into a list pretty easily.

My solution takes advantage of reduce():

const likesByAuthor = (blogs) =>{
    return blogs.reduce((likes, blog) => {
        if (blog.likes)
            if (likes[blog.author])
                likes[blog.author] += blog.likes;
            else
                likes[blog.author] = blog.likes;
        return likes;
    }, {});
}
Sign up to request clarification or add additional context in comments.

5 Comments

Your code is not working for me, I get this result: { _id: "5a422a851b54a676234d17f7" , title: "React patterns" , author: "Michael Chan" , url: "reactpatterns.com" , __v: 0 , Edsger W. Dijkstra: NaN , Robert C. Martin: NaN }
@AlejandroRosales Thanks for the comment. I missed a couple of details for it to work correctly. Check out my edit that should give a better result.
Wow, I did not know that you could use the reduce function like that, you're awesome, thank you!
@AlejandroRosales The main idea here is that reduce() can transform an array to any other data structure. Here I'm transforming the array into an object, but you can also transform an array into another array. In the later case, you should consider map() first.
@AlejandroRosales Also, you can do this with a manual for loop or even a forEach(). Your original attempt seems way more complicated than necessary. Remember to just do the work you need and no more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.