1
$\begingroup$

Is it possible to change the word order of a phrase by creating a list of possible values/variables and using the Sort function?

I want a specific word order always. $(a>b>c>d)$ But the values represented will change example to example. Associations may be what I'm actually trying to create, I'm not sure of the correct term.

Some examples of variables/associations:

a={"Left" or "Right" or "Top" or "Bottom"}
b={"Red" or "Blue" or "Green" or "Yellow"}
c={"Closing" or "Rolling" or "Running" or "Cleaning"}
d={"Paper" or "Note" or "Cat" or "Dog"}

Then I want to create a function:

neworder=Sort[a,b,c,d]

Then apply the function to a phrase (that has already been StringSplit):

neworder["Running","Dog","Blue"]

out = {"Blue","Running","Dog"}

Another example:

neworder["Red","Paper","Cleaning","Top"]

out = {"Top","Red","Cleaning","Paper"}

Is it possible to us Sort/SortBy in this manner? I know there are a few options in the way Sort works, but hadn't seen this method before. (Sorting a phrase by WordData, "PartsOfSpeech" is also on my radar, because that is essentially how I'm defining my variables/associations.)

$\endgroup$
2
  • $\begingroup$ Aren't "Left" and"Blue" the same part of speech? $\endgroup$
    – BlacKow
    Apr 8, 2016 at 15:30
  • $\begingroup$ @BlacKow Correct. Maintaining control of the difference between directional and color words felt important when I began thinking about this, so that's why the sorting by PartsOfSpeech is kind of an after thought. I'm working through your suggestion below, and it seems to be on the same track as I was hoping this could work. $\endgroup$ Apr 8, 2016 at 15:36

1 Answer 1

2
$\begingroup$

Straightforward way:

a = {"Left", "Right", "Top", "Bottom"};
b = {"Red", "Blue", "Green", "Yellow"};
c = {"Closing", "Rolling", "Running", "Cleaning"};
d = {"Paper", "Note", "Cat", "Dog"};
weights = 
  Transpose@
     Flatten[#, 
      1] &@(Transpose@{#1, ConstantArray[#2, Length@#1]} & @@@ {{a, 
       1}, {b, 2}, {c, 3}, {d, 4}});


sort[phrase_, weights_] := 
  SortBy[phrase, First@Pick[weights[[2]], weights[[1]], #] &];
sort[{"Red", "Paper", "Cleaning", "Top"}, weights]

{"Top", "Red", "Cleaning", "Paper"}

Or if you want to deal with "unknown" words by placing them in the end.

sort[phrase_, weights_] := 
  SortBy[phrase, 
   If[# == {}, Infinity, First[#]] &@
     Pick[weights[[2]], weights[[1]], #] &];
sort[{"Red", "blah", "Paper", "Cleaning", "Top", "babah"}, weights]

{"Top", "Red", "Cleaning", "Paper", "babah", "blah"}

You can of course define weights any way you want. I just followed your data.

Update If your phrase consists of words from list a only, the order will be changed, which I think is bad. So I modified the sorting function:

sort3[phrase_, weights_] := Module[{phind},
   phind = MapIndexed[{#1, First@#2} &, phrase];
   First@Transpose@
     SortBy[phind, 
      Function[x, 
         If[x == {}, 1^-10 #[[2]] + 10^10, First[x] + 1^-10 #[[2]]]]@
        Pick[weights[[2]], weights[[1]], #[[1]]] &]
   ];

So now compare

sort[{"Red", "Green", "Blue", "Yellow"}, weights]
(*{"Blue", "Green", "Red", "Yellow"}*)
sort3[{"Red", "Green", "Blue", "Yellow"}, weights]
(*{"Red", "Green", "Blue", "Yellow"}*)

sort[{"Red", "Green", "bub", "Blue", "ash", "Yellow"}, weights]
(*{"Blue", "Green", "Red", "Yellow", "ash", "bub"}*)
sort3[{"Red", "Green", "bub", "Blue", "ash", "Yellow"}, weights]
(*{"Red", "Green", "Blue", "Yellow", "bub", "ash"}*)

Now the sorting function accounts for position in the original phrase.

$\endgroup$
3
  • $\begingroup$ I was able to replicate your code and results successfully. You anticipated a follow up question I was going to have with your explanation of how to deal with unknown words. Bravo. How many examples could I have in my variables? Such as: a={100 examples}... zz={100 examples} $\endgroup$ Apr 8, 2016 at 15:52
  • $\begingroup$ @JonathanKolar You can have weights list of any length. Keep in mind that Pick will traverse the the whole list. So if you want to be efficient you can explore SelectFirst instead of Pick to see if it's better. Also at some point it makes sense to sort your weights and then perform search in sorted list. $\endgroup$
    – BlacKow
    Apr 8, 2016 at 16:19
  • $\begingroup$ @JonathanKolar Updated the sorting slightly, so it won't change order of words having same weight. $\endgroup$
    – BlacKow
    Apr 8, 2016 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.