2

I'm learning coding, and one of the assignments is to return keys is return the names of people who like the same TV show.

I have managed to get it working and to pass TDD, but I'm wondering if I've taken the 'long way around' and that maybe there is a simpler solution?

Here is the setup and test:

class TestFriends < MiniTest::Test

  def setup

    @person1 = {
      name: "Rick",
      age: 12,
      monies: 1,
      friends: ["Jay","Keith","Dave", "Val"],
      favourites: {
        tv_show: "Friends",
        things_to_eat: ["charcuterie"]
      }
    }

    @person2 = {
      name: "Jay",
      age: 15,
      monies: 2,
      friends: ["Keith"],
      favourites: {
        tv_show: "Friends",
        things_to_eat: ["soup","bread"]
      }
    }

    @person3 = {
      name: "Val",
      age: 18,
      monies: 20,
      friends: ["Rick", "Jay"],
      favourites: {
        tv_show: "Pokemon",
        things_to_eat: ["ratatouille", "stew"]
      }
    }

    @people = [@person1, @person2, @person3]

      end

      def test_shared_tv_shows
        expected = ["Rick", "Jay"]

        actual = tv_show(@people)

        assert_equal(expected, actual)
      end
    end

And here is the solution that I found:

def tv_show(people_list)
  tv_friends = {}
  for person in people_list
    if tv_friends.key?(person[:favourites][:tv_show]) == false
      tv_friends[person[:favourites][:tv_show]] = [person[:name]]
    else
      tv_friends[person[:favourites][:tv_show]] << person[:name]
    end
  end
  for array in tv_friends.values()
     if array.length() > 1
      return array
    end
  end
end

It passes, but is there a better way of doing this?

1 Answer 1

1

I think you could replace those for loops with the Array#each. But in your case, as you're creating a hash with the values in people_list, then you could use the Enumerable#each_with_object assigning a new Hash as its object argument, this way you have your own person hash from the people_list and also a new "empty" hash to start filling as you need.

To check if your inner hash has a key with the value person[:favourites][:tv_show] you can check for its value just as a boolean one, the comparison with false can be skipped, the value will be evaluated as false or true by your if statement.

You can create the variables tv_show and name to reduce a little bit the code, and then over your tv_friends hash to select among its values the one that has a length greater than 1. As this will give you an array inside an array you can get from this the first element with first (or [0]).

def tv_show(people_list)
  tv_friends = people_list.each_with_object(Hash.new({})) do |person, hash|
    tv_show = person[:favourites][:tv_show]
    name    = person[:name]

    hash.key?(tv_show) ? hash[tv_show] << name : hash[tv_show] = [name]
  end
  tv_friends.values.select { |value| value.length > 1 }.first
end

Also you can omit parentheses when the method call doesn't have arguments.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow thanks man this is the neatest solution that our class has seen so far!
I'm sure there are better solutions, but if this helps you I'm glad.

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.