Question

I have a grid that represents an X, Y matrix, stored as a hash here.

Some points on the X Y matrix may have values (as type string), and some may not.

A typical grid could look like this:

{[9, 5]=>"Alaina", [10, 3]=>"Courtney", [11, 1]=>"Gladys", [8, 7]=>"Alford", [14, 11]=>"Lesley", [17, 2]=>"Lawson", [0, 5]=>"Katrine", [2, 1]=>"Tyra", [3, 3]=>"Fredy", [1, 7]=>"Magnus", [6, 9]=>"Nels", [7, 11]=>"Kylie", [11, 0]=>"Kellen", [10, 2]=>"Johan", [14, 10]=>"Justice", [0, 4]=>"Barton", [2, 0]=>"Charley", [3, 2]=>"Magnolia", [1, 6]=>"Maximo", [7, 10]=>"Olga", [19, 5]=>"Isadore", [16, 3]=>"Delfina", [17, 1]=>"Noe", [20, 11]=>"Francis", [10, 5]=>"Creola", [9, 3]=>"Bulah", [8, 1]=>"Lempi", [11, 7]=>"Raquel", [13, 11]=>"Jace", [1, 5]=>"Garth", [3, 1]=>"Ernest", [2, 3]=>"Malcolm", [0, 7]=>"Alejandrin", [7, 9]=>"Marina", [6, 11]=>"Otilia", [16, 2]=>"Hailey", [20, 10]=>"Brandt", [8, 0]=>"Madeline", [9, 2]=>"Leanne", [13, 10]=>"Jenifer", [1, 4]=>"Humberto", [3, 0]=>"Nicholaus", [2, 2]=>"Nadia", [0, 6]=>"Abigail", [6, 10]=>"Zola", [20, 5]=>"Clementina", [23, 3]=>"Alvah", [19, 11]=>"Wallace", [11, 5]=>"Tracey", [8, 3]=>"Hulda", [9, 1]=>"Jedidiah", [10, 7]=>"Annetta", [12, 11]=>"Nicole", [2, 5]=>"Alison", [0, 1]=>"Wilma", [1, 3]=>"Shana", [3, 7]=>"Judd", [4, 9]=>"Lucio", [5, 11]=>"Hardy", [19, 10]=>"Immanuel", [9, 0]=>"Uriel", [8, 2]=>"Milton", [12, 10]=>"Elody", [5, 10]=>"Alexanne", [1, 2]=>"Lauretta", [0, 0]=>"Louvenia", [2, 4]=>"Adelia", [21, 5]=>"Erling", [18, 11]=>"Corene", [22, 3]=>"Haskell", [11, 11]=>"Leta", [10, 9]=>"Terrence", [14, 1]=>"Giuseppe", [15, 3]=>"Silas", [12, 5]=>"Johnnie", [4, 11]=>"Aurelie", [5, 9]=>"Meggie", [2, 7]=>"Phoebe", [0, 3]=>"Sister", [1, 1]=>"Violet", [3, 5]=>"Lilian", [18, 10]=>"Eusebio", [11, 10]=>"Emma", [15, 2]=>"Theodore", [14, 0]=>"Cassidy", [4, 10]=>"Edmund", [2, 6]=>"Claire", [0, 2]=>"Madisen", [1, 0]=>"Kasey", [3, 4]=>"Elijah", [17, 11]=>"Susana", [20, 1]=>"Nicklaus", [21, 3]=>"Kelsie", [10, 11]=>"Garnett", [11, 9]=>"Emanuel", [15, 1]=>"Louvenia", [14, 3]=>"Otho", [13, 5]=>"Vincenza", [3, 11]=>"Tate", [2, 9]=>"Beau", [5, 7]=>"Jason", [6, 1]=>"Jayde", [7, 3]=>"Lamont", [4, 5]=>"Curt", [17, 10]=>"Mack", [21, 2]=>"Lilyan", [10, 10]=>"Ruthe", [14, 2]=>"Georgianna", [4, 4]=>"Nyasia", [6, 0]=>"Sadie", [16, 11]=>"Emil", [21, 1]=>"Melba", [20, 3]=>"Delia", [3, 10]=>"Rosalee", [2, 8]=>"Myrtle", [7, 2]=>"Rigoberto", [14, 5]=>"Jedidiah", [13, 3]=>"Flavie", [12, 1]=>"Evie", [8, 9]=>"Olaf", [9, 11]=>"Stan", [20, 2]=>"Judge", [5, 5]=>"Cassie", [7, 1]=>"Gracie", [6, 3]=>"Armando", [4, 7]=>"Delia", [3, 9]=>"Marley", [16, 10]=>"Robyn", [2, 11]=>"Richie", [12, 0]=>"Gilberto", [13, 2]=>"Dedrick", [9, 10]=>"Liam", [5, 4]=>"Jabari", [7, 0]=>"Enola", [6, 2]=>"Lela", [3, 8]=>"Jade", [2, 10]=>"Johnson", [15, 5]=>"Willow", [12, 3]=>"Fredrick", [13, 1]=>"Beau", [9, 9]=>"Carlie", [8, 11]=>"Daisha", [6, 5]=>"Declan", [4, 1]=>"Carolina", [5, 3]=>"Cruz", [7, 7]=>"Jaime", [0, 9]=>"Anthony", [1, 11]=>"Esta", [13, 0]=>"Shaina", [12, 2]=>"Alec", [8, 10]=>"Lora", [6, 4]=>"Emely", [4, 0]=>"Rodger", [5, 2]=>"Cedrick", [0, 8]=>"Collin", [1, 10]=>"Armani", [16, 5]=>"Brooks", [19, 3]=>"Eleanora", [18, 1]=>"Alva", [7, 5]=>"Melissa", [5, 1]=>"Tabitha", [4, 3]=>"Aniya", [6, 7]=>"Marc", [1, 9]=>"Marjorie", [0, 11]=>"Arvilla", [19, 2]=>"Adela", [7, 4]=>"Zakary", [5, 0]=>"Emely", [4, 2]=>"Alison", [1, 8]=>"Lorenz", [0, 10]=>"Lisandro", [17, 5]=>"Aylin", [18, 3]=>"Giles", [19, 1]=>"Kyleigh", [8, 5]=>"Mary", [11, 3]=>"Claire", [10, 1]=>"Avis", [9, 7]=>"Manuela", [15, 11]=>"Chesley", [18, 2]=>"Kristopher", [24, 3]=>"Zola", [8, 4]=>"Pietro", [10, 0]=>"Delores", [11, 2]=>"Timmy", [15, 10]=>"Khalil", [18, 5]=>"Trudie", [17, 3]=>"Rafael", [16, 1]=>"Anthony"}

What I need to do though, is basically remove all the empty entries.

Let's say [17,3] => Raphael does not have an element in front of if (let's say - no [16,3] exists) then [17,3] should become [16,3] etc.

So basically all empty items will be popped off the vertical (row) structure of the hash.

Are there functions I should have a look at or is there an easy squash-like method that would just remove blanks and adjust and move other items?

Thanks in advance for your help.

Was it helpful?

Solution

Here's my shot at it (probably not the fastest possible):

data.group_by{|k,v| k[1]}.inject({}){|a,(k,v)|
  v.sort_by{|i| i[0][0]}.each_with_index{|elem,i|
    a[[i,elem[0][1]]] = elem[1]
  }
  a
}

And here's input subset suitable for testing:

{[9, 5]=>"Alaina", [10, 3]=>"Courtney", [11, 5]=>"Gladys", [8, 5]=>"Alford"}

which should result with:

{[0, 5]=>"Alford", [1, 5]=>"Alaina", [2, 5]=>"Gladys", [0, 3]=>"Courtney"}

Step-by-step explanation (you can experiment in irb):

We need group-by because we should process each row separately, so first we group records by row, making a hash of arrays (let's call each of these arrays r)

data.group_by{|k,v| k[1]}
# => {5=>[[[9, 5], "Alaina"], [[11, 5], "Gladys"], [[8, 5], "Alford"]], 3=>[[[10, 3], "Courtney"]]}

inject is there so we can create output hash, we start with the empty one and we'll add "transformed" element at a time. Transformation is simply replacing the column indexes with "compacted" indexes, so the idea is to somehow map array [8, 9, 11] to [0, 1, 2] (when processing row 5). That's why we need to sort array r (let's call the sorted array rs):

r = [[[9, 5], "Alaina"], [[11, 5], "Gladys"], [[8, 5], "Alford"]]
rs = r.sort_by{|i| i[0][0]}
#=> [[[8, 5], "Alford"], [[9, 5], "Alaina"], [[11, 5], "Gladys"]]

And then assign each element in rs an index, starting from 0. We use each_with_index for that, so that in elem, i we get pairs such as

[[8, 5], "Alford"], 0
[[9, 5], "Alaina"], 1
[[11, 5], "Gladys"], 2

and now we have all needed numbers to fill in the resulting hash a:

a[[i,elem[0][1]]] = elem[1]

so

a[[0,5]] = 'Alford'
a[[1,5]] = 'Alaina'
etc.

We need to return a (accumulator) from a block for inject to work properly.

That should be it. :)

OTHER TIPS

Ok... I think i get what you want it to do; Here is how I would do it:

data = # the hash in the format above
rows = [] # a new array

# then place each row in the entry of rows corresponding to it's y value at
# the index of it's x value
data.each_pair {|key, value| rows[key[1]] ||= []; rows[key[1]][key[0]] = value }

# compact the x values (if there is an adjacent lower x available move to it)
# this is what i believe you meant in your example
rows.map(&:compact!)

# clear out the old data
data = {}

# fill the hash back up using the new compacted data
rows.each_with_index { |xs, y| xs.each_with_index { |entry, x| data[[x,y]] = entry } }

tested it on your data (along with adding some more difficult x values) and it seems to work :)

Roja

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top