Ruby Forum Rails France > aide "sort" d'index trop facile, mais je n'y arrive pas

Posted by pierrederome (Guest)
on 07.05.2008 11:25
(Received via mailing list)
bonjour,

j'ai un array, par exemple

a = [ 10, 2, 20, 14, 33]

je veux obtenir:

ordre = [5, 3, 4, 1, 2]

je suis sûr que ça s'écrit en une toute petite ligne propre... je
n'arrive qu'à le faire en compliqué, tordu, moche ...


merci
Posted by Michel Belleville (Guest)
on 07.05.2008 11:27
(Received via mailing list)
Je ne vois pas de rapport entre les deux tableaux...
Posted by philippe lachaise (Guest)
on 07.05.2008 11:34
(Received via mailing list)
>> Je ne vois pas de rapport entre les deux tableaux...

Moi non plus :-/
C'est un test de QI ?   ;-)

--
IciMarché fédère l'e-commerce de proximité
http://icimarche.fr
Posted by Michel Belleville (Guest)
on 07.05.2008 11:37
(Received via mailing list)
Si, il veut trier le tableau, puis obtenir l'ordre des clés initiales.
Posted by pierrederome (Guest)
on 07.05.2008 11:38
(Received via mailing list)
merci de votre intérêt..

a = [ 10, 2, 20, 14, 33]

un tri descendant donne

a_trié = [ 33, 20, 14, 10, 2]

mais je veux un tri des index (et je les fais commencer à 1 et pas 0)

on avait [1-10, 2-2, 3-20, 4-14, 5-33]
on a [5-33, 3-20, 4-14, 1-10, 2-2]

donc avec seulement les index:

ordre = [5, 3, 4, 1, 2]

voilà, j'espère que c'est plus clair

On 7 mai, 11:27, "Michel Belleville" <michel.bellevi...@gmail.com>
Posted by Baptiste Decroix (Guest)
on 07.05.2008 11:44
(Received via mailing list)
Quelque chose comme ca?

a = [ 10, 2, 20, 14, 33]
i = [ 1, 2, 3, 4, 5 ]
i.sort{|i1, i2| a[i2-1] <=> a[i1-1] }

Le 7 mai 2008 11:37, pierrederome <pierrederome@gmail.com> a écrit :
>  mais je veux un tri des index (et je les fais commencer à 1 et pas 0)
>
>  On 7 mai, 11:27, "Michel Belleville" <michel.bellevi...@gmail.com>
>  wrote:
>
>
> > Je ne vois pas de rapport entre les deux tableaux...
>  >
>



--
Baptiste
Posted by Jean-François Trân (Guest)
on 07.05.2008 11:44
(Received via mailing list)
Le 7 mai 2008 11:24, pierrederome  a écrit :
>
>  je suis sûr que ça s'écrit en une toute petite ligne propre... je
>  n'arrive qu'à le faire en compliqué, tordu, moche ...

Mon idée sur laquelle je partirai, serait de trier a par ordre
décroissant et d'effectuer exactement les mêmes opérations
(par exemple de permutation) sur [1, 2, 3, 4, 5].

à toi de prendre un algo de tri le plus 
adapté.
   -- Jean-François.

--
RailsCamp Paris le samedi 17 mai 2008 :
http://rubyfrance.org/evenements/railscamp-paris
Posted by Thibaut Barrère (thbar)
on 07.05.2008 11:44
(Received via mailing list)
hello,

je te propose ceci (d'autres amélioreront peut être! c'est le ruby
quizz de l'après midi):

irb(main):037:0> a
=> [10, 2, 20, 14, 33]
irb(main):038:0> a.map { |e| a.sort.index(e)+1 }.reverse
=> [5, 3, 4, 1, 2]

bon après midi

Thibaut
--
http://blog.logeek.fr - learning content for developers
http://evolvingworker.com - tools for a better day
Posted by Michel Belleville (Guest)
on 07.05.2008 11:47
(Received via mailing list)
>  a.map { |e| a.sort.index(e)+1 }.reverse

C'est élégant en effet.
Posted by Michel Belleville (Guest)
on 07.05.2008 11:49
(Received via mailing list)
Pour optimiser, on pourrait faire :
b = a.sort
a.map { |e| b.index(e) + 1 }.reverse

Si le tableau est grand ça accélèrera pas mal.

Sinon ça ne marchera pas avec des doublons...
Posted by Jean-François Trân (Guest)
on 07.05.2008 11:49
(Received via mailing list)
Le 7 mai 2008 11:44, Thibaut Barrère a écrit :
>  => [5, 3, 4, 1, 2]
à la louche, on dirait que ça a une complexité en O(n^2), non  ?
Et tu tries a à chaque itération...

   -- Jean-François

--
Vice-président de l'association Ruby France.
RailsCamp Paris le samedi 17 mai 2008 :
http://rubyfrance.org/evenements/railscamp-paris
Posted by Jean-François Trân (Guest)
on 07.05.2008 11:56
(Received via mailing list)
Le 7 mai 2008 11:43, Baptiste Decroix a écrit :
>
>  Quelque chose comme ca?
>
>
>  a = [ 10, 2, 20, 14, 33]
>  i = [ 1, 2, 3, 4, 5 ]
>  i.sort{|i1, i2| a[i2-1] <=> a[i1-1] }

Ouais, c'est mieux que mon idée puisque là c'est Ruby qui trie à 
notre place :)

Du coup, on peut faire :

i.sort_by { |i| a[i-1] }

les transformations schwartziennes sont vos amies :-)

   -- Jean-François.

--
RailsCamp Paris le samedi 17 mai 2008 :
http://rubyfrance.org/evenements/railscamp-paris
Posted by Lionel Bouton (Guest)
on 07.05.2008 11:59
(Received via mailing list)
Thibaut Barrère wrote the following on 07.05.2008 11:44 :
> hello,
>
> je te propose ceci (d'autres amélioreront peut être! c'est le ruby
> quizz de l'après midi):
>
> irb(main):037:0> a
> => [10, 2, 20, 14, 33]
> irb(main):038:0> a.map { |e| a.sort.index(e)+1 }.reverse
> => [5, 3, 4, 1, 2]
>   

Ca ne marche pas si tu as deux éléments identiques dans le tableau de
départ (sans compter que faire un sort + index pour chaque entrée du
tableau va vite devenir prohibitif).

a = [ 10, 2, 20, 14, 33 ]
b = []
a.each_with_index { |v,i| b[i] = [ v, i + 1 ] }
b.sort_by { |o| o[0] }.map { |v| v[1] }

=> [2, 1, 4, 3, 5]

On peut s'en sortir en une ligne avec map_with_index qui existe dans
Ruby 1.9 (et dans certaines gems) si j'ai bonne mémoire :

a.map_with_index { |v,i| [ v, i + 1 ] }.sort_by { |o| o[0] }.map { |v|
v[1] }

Lionel
Posted by Thibaut Barrère (thbar)
on 07.05.2008 12:00
(Received via mailing list)
> à la louche, on dirait que ça a une complexité en O(n^2), non  ?
> Et tu tries a à chaque itération...

Ah oui ça c'est tout moi: je ne cherche à optimiser que si le besoin
apparaît.

-- Thibaut
Posted by Baptiste Decroix (Guest)
on 07.05.2008 12:02
(Received via mailing list)
>  Du coup, on peut faire :
>
>  i.sort_by { |i| a[i-1] }
>
>  les transformations schwartziennes sont vos amies :-)
>

En fait c'était pour trier directement par ordre décroissant sans
avoir à utiliser de reverse.
Mais je n'avais jamais pensé à utiliser sort_by de cette facon, je retiens 
:-)

Joli quizz!
--
Baptiste
Posted by Thibaut Barrère (thbar)
on 07.05.2008 12:03
(Received via mailing list)
> Ah oui ça c'est tout moi: je ne cherche à optimiser que si le besoin apparaît.

Et pour le savoir, on gagnera à affiner la "compréhension du besoin"
en demandant au client (Pierre):
- combien d'éléments y-a-t-il dans ton tableau, en moyenne ?
- peut-il y avoir des doublons ?

-- Thibaut
Posted by Thibaut Barrère (thbar)
on 07.05.2008 12:04
(Received via mailing list)
> i.sort_by { |i| a[i-1] }

J'aime beaucoup!

-- Thibaut
Posted by pierrederome (Guest)
on 07.05.2008 12:09
(Received via mailing list)
merci beaucoup,
vous êtes top !

à la fin, j'ai fait:

    b = []
    a.each_with_index { |v,i| b[i] = [ v, i ] }
    @ordre=b.sort_by { |o| o[0] }.map { |v| v[1] }.reverse

et c'est nickel, effectivement j'ai ruby 1.8 et pas 1.9

je suis content d'avoir demandé pcq je n'aurais pas fait si simple, et
j'ai appris des trucs !
Posted by Jean-Baptiste Escoyez (Guest)
on 07.05.2008 13:32
(Received via mailing list)
On 07 May 2008, at 11:59, Lionel Bouton wrote:

> On peut s'en sortir en une ligne avec map_with_index qui existe dans
> Ruby 1.9 (et dans certaines gems) si j'ai bonne mémoire :
>
> a.map_with_index { |v,i| [ v, i + 1 ] }.sort_by { |o| o[0] }.map { |v|
> v[1] }

J'arrive un peu après la bataille :) mais si vous voulez faire ça avec
ruby 1.8, vous pouvez faire:

a.enum_with_index.map {|v, i| ... }

Problème intéressant en tout cas.

Ca me fait un peu penser à http://www.rubyquiz.com/ .

--
Jean-Baptiste Escoyez
Belighted.com | Web 2.0 Consulting & Training
Email : jbe@belighted.com | Phone: +32 486 377593
Posted by Jean-François Trân (Guest)
on 07.05.2008 13:46
(Received via mailing list)
Le 7 mai 2008 13:31, Jean-Baptiste Escoyez a écrit :
>
>  On 07 May 2008, at 11:59, Lionel Bouton wrote:
>
>  > On peut s'en sortir en une ligne avec map_with_index qui existe dans
>  > Ruby 1.9 (et dans certaines gems) si j'ai bonne mémoire :
>  >
>  > a.map_with_index { |v,i| [ v, i + 1 ] }.sort_by { |o| o[0] }.map { |v|
>  > v[1] }

je trouve ... sort_by { |o| o.first }.map { |v| v.last }

un poil plus long mais nettement plus lisible.

>  J'arrive un peu après la bataille :) mais si vous voulez faire ça avec
>  ruby 1.8, vous pouvez faire:
>
>  a.enum_with_index.map {|v, i| ... }

il faut faire un require 'enumerator' au préalable.

En 1.9, sans avoir à faire de require, on a l'élégant :

a.map.with_index { |v, i| ... }

    -- Jean-François.

--
RailsCamp Paris le samedi 17 mai 2008 :
http://rubyfrance.org/evenements/railscamp-paris