0

Currently I have a list of random games in an array.

games=[["Game1", 2014, "Creator1", "Creator2", "Creator3"],
       ["Game4", 2013, "Creator7", "Creator10"],
       ["Game2", 2014, "Creator1"],
       ["Game6", 2012, "Creator9"],
       ["Game3", 1990, "Creator2", "Creator11"],
       ["Game9", 2014, "Creator4"]]

#Which looks like this
Title, Year, Creators
Game1, 2014, Creator1, Creator2, Creator3
Game4, 2013, Creator7, Creator10
Game2, 2014, Creator1
Game6, 2012, Creator9
Game3, 1990, Creator2, Creator11
Game9, 2014, Creator4

I wish to sort the data in the following order

  • Year
  • Title

Into

Creator1  => Game1, Game2
Creator10 => Game4
Creator11 => Game3
Creator2  => Game3, Game1 #<- year: 1990, 2014
Creator3  => Game1
Creator4  => Game9
Creator7  => Game4

Currently, I have

def creator_list(games)
    games.sort_by{|x|[-x[1].to_i,x[0]]}
         .inject(Hash.new{|h,k|h[k]=Array.new}) {|h, rw|
         rw[2].each do |a|
             h[a] << rw[0]
         end
         h
         }.to_a.sort_by{|x|x[0]}
end

This my best result so far. However, I wish to know if there are any other algorithm or another approach to improve this?

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
Charlie
  • 13
  • 2
  • 1
    The downvote and vote to close are probably because what you say is an array is not. It may be a table, but that's not a Ruby object. I assume you want something like `arr = [["Game1", 2014, "Creator1", "Creator2", "Creator3"], ["Game4", 2013, "Creator1",...]`. You need to edit your question to correct that. Until you do, downvotes and votes to close will surely pile up. Also, it better be "pretty darn quick" if your computer is less than, say, 30 years old. – Cary Swoveland Feb 26 '15 at 06:59
  • Another reason for showing you data as an actual array is so that readers who want to offer a (tested) solution can simply cut and paste the array, rather than being obliged to construct the array from the data in the table. – Cary Swoveland Feb 26 '15 at 07:09
  • @CarySwoveland Thank you for pointing that out! I'll learn more on the "do and don't" on stackoverflow – Charlie Feb 26 '15 at 07:12
  • It was easier to reformat so it can be read without the need for horizontal scrolling than to try to explain why and how you should do that. Now show your desired output as a hash: `{ "Creator1" => ["Game1", "Game2"], "Creator10"=>["Game4"], ...]`. Then remove the tables which are no longer needed. – Cary Swoveland Feb 26 '15 at 07:21
  • You have just changed the question by putting "Creators" in arrays. That's against the rules, for a very good reason. Anyone working on a solution for you will be really annoyed. Please roll your question back. If you want to ask a different question, post it separately. – Cary Swoveland Feb 26 '15 at 08:10
  • You have also changed the example! Not only that, but you've added rows. When you give an example you want to make it as brief as possible to make the point. In case you will not be back for awhile, I will roll back your question. If you want to edit, that's fine, as long as you don't change the question. – Cary Swoveland Feb 26 '15 at 09:06
  • yeah I tried to make it brief by making an example you saw. but it wasnt working as intended. which was why i change it to the smaller and actual dataset – Charlie Feb 26 '15 at 12:43

1 Answers1

0

[Edit: after posting this answer I noticed that you want to sort on year then the "Creator" field. That's not possible, as each "Creator" will have multiple games with different years. If you want to use years as a sort criterion, you will have to specify how that would be done, but it's too late to do that for this question.]

I had a problem running your code, but the basic idea is fine. One thing I suggest you fix is the sorting. By sorting strings, "Creator11" comes before "Creator2".

There are many ways to do this, and I doubt that you'd notice performance differences unless you had a very large array (including your method). I'll give a solution that uses the form of Hash#update (aka merge!) that uses a block to determine the value when both hashes being merged have the same key. Someone else may offer a solution that use the method Enumerable#group_by.

def creator_list(games)
  Hash[games.each_with_object({}) do |(game, year, *creators),h|
    creators.each { |c| h.update(c=>[game]) { |_,ov,nv| ov+nv } }
  end.sort_by { |k,_| k[/\d+$/].to_i }]
end

creator_list(games)
  #=> {"Creator1" =>["Game1", "Game2"],
  #    "Creator2" =>["Game1", "Game3"],
  #    "Creator3" =>["Game1"],
  #    "Creator4" =>["Game9"],
  #    "Creator7" =>["Game4"],
  #    "Creator9" =>["Game6"],
  #    "Creator10"=>["Game4"],
  #    "Creator11"=>["Game3"]} 

Where you see _ for a block variable, that's to signify that I'm not using that variable in the block. (_ is a variable, however, and therefore is assigned a value).

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100