From: Douglas Seifert Date: 2013-06-18T06:35:11+09:00 Subject: Re: Compare and sort one array according to another. --047d7b5d474ef686cf04df605ef2 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable You have said that the size of your two arrays is small, so the fact that the find_index based solution is o(n^2) probably doesn't matter. For kicks, a o(n) solution compared to the o(n^2) solution here: https://gist.github.com/seifertd/5800639 It involves precomputing a lookup index for the data you need to sort. -Doug On Mon, Jun 17, 2013 at 1:40 PM, Jes=FAs Gabriel y Gal=E1n < jgabrielygalan@gmail.com> wrote: > On Mon, Jun 17, 2013 at 10:39 PM, Jes=FAs Gabriel y Gal=E1n > wrote: > > On Mon, Jun 17, 2013 at 9:56 PM, masta Blasta > wrote: > >> Joel Pearson wrote in post #1112686: > >>> masta Blasta wrote in post #1112677: > >>>> Joel Pearson wrote in post #1112665: > >>>>> If the items within each array belong to each other, how about a > >>>>> multidimensional array? > >>>>> > >>>>> arr =3D [ > >>>>> [ Obj1(prop1, prop2, id), OthrObj1(prop1, prop2, ref_id) ], > >>>>> [ Obj2(prop1, prop2, id), OthrObj2(prop1, prop2, ref_id) ], > >>>>> [ Obj3(prop1, prop2, id), OthrObj3(prop1, prop2, ref_id) ] > >>>>> ] > >>>>> > >>>>> > >>>>> All the sorting is dealt with together then: > >>>>> > >>>>> sorted_arr =3D arr.sort_by { |obj1, obj2| obj1.id } > >>>> > >>>> I don't quite understand everything that's happening here. Can you > >>>> elaborate a bit more on your solution. > >>> > >>> I'm going by your comment here: > >>> "The objects in arr2 have a 1-1 relationship with the objects in arr1= " > >>> > >>> If the objects are interlinked, rather than trying to keep two separa= te > >>> arrays and sorting them side-by-side (which can easily go wrong), you > >>> could simply connect the pairs into their own arrays all inside anoth= er > >>> array. > >>> > >>> This has the benefit that once you put the pair into their own array, > >>> they are connected without you having to worry about having to do > >>> everything the same with array1 and array2. > >>> > >>> Then you can iterate through the large array like this: > >>> > >>> arr.each { |subarray| some_method( subarray[0], subarray[1] ) } > >>> > >>> In this example you can access each of the smaller arrays inside your > >>> array. [0] is each object and [1] is each otherobject > >>> > >>> Or like this: > >>> > >>> arr.each { |object, otherobject| some_method( object, otherobject ) } > >>> > >>> This example is functionally the same as the previous one, but you're > >>> using parallel assignment to place each object from the array into it= s > >>> own variable so it's easier to read. > >>> > >>> Using this approach, you can sort the larger array containing objects > >>> and otherobjects by whatever criteria you want, and they'll stay > >>> together as a pair within the larger array. > >>> > >>> This will sort each array within the parent by the first object's id: > >>> > >>> arr =3D arr.sort_by { |object, otherobject| object.id } > >>> > >>> This does the same thing, but with the second object's id: > >>> > >>> arr =3D arr.sort_by { |object, otherobject| otherobject.id } > >>> > >>> The best way to grasp how this is works is to do it in IRB and play > >>> around with the results. > >> > >> I just learned something new about ordering arrays! However this doesn= 't > >> actually solve the original problem. Your solution expects both arrays > >> to be properly sorted, and then keeps them together if one or the othe= r > >> is re-ordered. > >> > >> Originally only one of the arrays was properly sorted, and the other h= ad > >> then to be ordered to match. > >> > >> Here is some better sample data: > >> terms =3D [ > >> {:id=3D>3, :name=3D>"term1", :version=3D>2}, > >> {:id=3D>4, :name=3D>"term2", :version=3D>2}, > >> {:id=3D>8, :name=3D>"term3", :version=3D>1} > >> ] > >> > >> arr2 =3D [ > >> {:term_id=3D>4, :name=3D>"assoc1"}, > >> {:term_id=3D>8, :name=3D>"assoc2"}, > >> {:term_id=3D>3, :name=3D>"assoc3"} > >> ] > >> > >> so 'terms' is properly sorted, and now we want arr2 to follow that > >> order. So after our operation arr2 should look like: > >> > >> arr2 =3D [ > >> {:term_id=3D>3, :name=3D>"assoc3"}, > >> {:term_id=3D>4, :name=3D>"assoc1"}, > >> {:term_id=3D>8, :name=3D>"assoc2"} > >> > >> ] > >> > >> These are ActiveRecord objects. A SQL solution is possible but the que= ry > >> is painfully long due to complex associations. Since the arrays are > >> usually small 3-5 records, i was hoping i could just sort them > >> programmatically. > > > > Did you try Robert Klemme's solution? Translated to this new example: > > > > Typo: that should have been > > > arr2.sort_by {|o| terms.find_index {|a| o[:term_id] =3D=3D a[:id]}} > > > > =3D> [{:term_id=3D>3, :name=3D>"assoc3"}, {:term_id=3D>4, :name=3D>"ass= oc1"}, > > {:term_id=3D>8, :name=3D>"assoc2"}] > > > > Jesus. > > --047d7b5d474ef686cf04df605ef2 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
You have said that the size of your two arrays is small, s= o the fact that the find_index based solution is o(n^2) probably doesn'= t matter. =A0For kicks, a o(n) solution compared to the o(n^2) solution her= e:

https://gist.githu= b.com/seifertd/5800639

It involves precomputing a lo= okup index for the data you need to sort.

-Doug


O= n Mon, Jun 17, 2013 at 1:40 PM, Jes=FAs Gabriel y Gal=E1n <jgabriel= ygalan@gmail.com> wrote:
On M= on, Jun 17, 2013 at 10:39 PM, Jes=FAs Gabriel y Gal=E1n
<jgabrielygalan@gmail.com> wrote:
> On Mon, Jun 17, 2013 at 9:56 PM, masta Blasta <
lists@ruby-forum.com> wrote:
>> Joel Pearson wrote in post #1112686:
>>> masta Blasta wrote in post #1112677:
>>>> Joel Pearson wrote in post #1112665:
>>>>> If the items within each array belong to each other, h= ow about a
>>>>> multidimensional array?
>>>>>
>>>>> arr =3D [
>>>>> [ Obj1(prop1, prop2, id), OthrObj1(prop1, prop2, ref_i= d) ],
>>>>> [ Obj2(prop1, prop2, id), OthrObj2(prop1, prop2, ref_i= d) ],
>>>>> [ Obj3(prop1, prop2, id), OthrObj3(prop1, prop2, ref_i= d) ]
>>>>> ]
>>>>>
>>>>>
>>>>> All the sorting is dealt with together then:
>>>>>
>>>>> sorted_arr =3D arr.sort_by { |obj1, obj2| obj1.id }
>>>>
>>>> I don't quite understand everything that's happeni= ng here. Can you
>>>> elaborate a bit more on your solution.
>>>
>>> I'm going by your comment here:
>>> "The objects in arr2 have a 1-1 relationship with the obj= ects in arr1"
>>>
>>> If the objects are interlinked, rather than trying to keep two= separate
>>> arrays and sorting them side-by-side (which can easily go wron= g), you
>>> could simply connect the pairs into their own arrays all insid= e another
>>> array.
>>>
>>> This has the benefit that once you put the pair into their own= array,
>>> they are connected without you having to worry about having to= do
>>> everything the same with array1 and array2.
>>>
>>> Then you can iterate through the large array like this:
>>>
>>> arr.each { |subarray| some_method( subarray[0], subarray[1] ) = }
>>>
>>> In this example you can access each of the smaller arrays insi= de your
>>> array. [0] is each object and [1] is each otherobject
>>>
>>> Or like this:
>>>
>>> arr.each { |object, otherobject| some_method( object, otherobj= ect ) }
>>>
>>> This example is functionally the same as the previous one, but= you're
>>> using parallel assignment to place each object from the array = into its
>>> own variable so it's easier to read.
>>>
>>> Using this approach, you can sort the larger array containing = objects
>>> and otherobjects by whatever criteria you want, and they'l= l stay
>>> together as a pair within the larger array.
>>>
>>> This will sort each array within the parent by the first objec= t's id:
>>>
>>> arr =3D arr.sort_by { |object, otherobject| object.id }
>>>
>>> This does the same thing, but with the second object's id:=
>>>
>>> arr =3D arr.sort_by { |object, otherobject| otherobject.id }
>>>
>>> The best way to grasp how this is works is to do it in IRB and= play
>>> around with the results.
>>
>> I just learned something new about ordering arrays! However this d= oesn't
>> actually solve the original problem. Your solution expects both ar= rays
>> to be properly sorted, and then keeps them together if one or the = other
>> is re-ordered.
>>
>> Originally only one of the arrays was properly sorted, and the oth= er had
>> then to be ordered to match.
>>
>> Here is some better sample data:
>> terms =3D [
>> =A0 =A0 {:id=3D>3, :name=3D>"term1", :version=3D&g= t;2},
>> =A0 =A0 {:id=3D>4, :name=3D>"term2", :version=3D&g= t;2},
>> =A0 =A0 {:id=3D>8, :name=3D>"term3", :version=3D&g= t;1}
>> ]
>>
>> arr2 =3D [
>> =A0 =A0 {:term_id=3D>4, :name=3D>"assoc1"},
>> =A0 =A0 {:term_id=3D>8, :name=3D>"assoc2"},
>> =A0 =A0 {:term_id=3D>3, :name=3D>"assoc3"}
>> ]
>>
>> so 'terms' is properly sorted, and now we want arr2 to fol= low that
>> order. So after our operation arr2 should look like:
>>
>> arr2 =3D [
>> =A0 =A0 {:term_id=3D>3, :name=3D>"assoc3"},
>> =A0 =A0 {:term_id=3D>4, :name=3D>"assoc1"},
>> =A0 =A0 {:term_id=3D>8, :name=3D>"assoc2"}
>>
>> ]
>>
>> These are ActiveRecord objects. A SQL solution is possible but the= query
>> is painfully long due to complex associations. Since the arrays ar= e
>> usually small 3-5 records, i was hoping i could just sort them
>> programmatically.
>
> Did you try Robert Klemme's solution? Translated to this new examp= le:
>

Typo: that should have been

> arr2.sort_by {|o| terms.find_index {|a| o[:term_id] =3D=3D a[:id]}}
>
> =3D> [{:term_id=3D>3, :name=3D>"assoc3"}, {:term_id= =3D>4, :name=3D>"assoc1"},
> {:term_id=3D>8, :name=3D>"assoc2"}]
>
> Jesus.


--047d7b5d474ef686cf04df605ef2--