2
\$\begingroup\$

I saw this question and wondered how it'd be best to accomplish this using Ramda.

I'm new to the library so I thought it'd be an interesting learning exercise.

I have a working solution but it seems overly complicated and verbose. I'd be grateful for any suggestions on what other ways it would be possible to achieve this output using Ramda.

I'm aware that this doesn't need a library; as I say, I approached it as a learning exercise.

Here's what I have:

const { addIndex, always, fromPairs, join, map, sort, toPairs, unnest } = R;

const song = {
  "99": [0, 7],
  "bottles": [1, 8],
  "of": [2, 9],
  "beer": [3, 10],
  "on": [4],
  "the": [5],
  "wall": [6]
};

const toSentence = join(' ');

const parsed = toSentence(
    map(
      ([_, word]) => word,
      sort(
        ([a, _], [b, __]) => a < b ? -1 : 1,
        unnest(
          map(
            ([word, indices]) => map(
              index => [index, word],
              indices,
            ),
            toPairs(song)
          )
        )
      )
    )
  )
  
console.dir(parsed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Reverse the order of the sort and the map, then the sort doesn't need to do \$n \cdot log(n)\$ array dereferences. Your sort function is unstable and won't preserve the ordering of equal elements. It doesn't matter in this problem; when it does matter, it's a source of nasty, subtle bugs, so always be aware of when you're doing that. \$\endgroup\$ Commented Apr 2, 2019 at 16:44
  • \$\begingroup\$ @OhMyGoodness Thank you for your comment, which is very useful! \$\endgroup\$ Commented Apr 3, 2019 at 7:47

2 Answers 2

1
\$\begingroup\$

This is a great question.

I found no easy Ramda functional way to solve this, but you could just use a forEach approach. I find it easier to read.

const {forEachObjIndexed, forEach} = R;

const song = {
  "99": [0, 7],
  "bottles": [1, 8],
  "of": [2, 9],
  "beer": [3, 10],
  "on": [4],
  "the": [5],
  "wall": [6]
};

let words = [];

forEachObjIndexed((indexes, word) => forEach(idx => words[idx] = word, indexes), song);

console.log(words.join(' '));
\$\endgroup\$
1
  • \$\begingroup\$ This is an interesting approach to the problem and I also find it easier to read than the code I had \$\endgroup\$ Commented Apr 3, 2019 at 8:00
1
\$\begingroup\$

Names

Variable names are very important,Try to keep the code understandable by defining named functions that relate to the abstract thing the do. (see example)

Same with the arguments. The names indices, and index are misleading. You are referring to the word position. Thus the names positions and position would be better suited. I would use pos rather than position

Redundant code

  • In the sorting compare function the two arguments _, and __ are not not needed. The return can be any number value -10 and -1 are equivalent, so use the sorter for a-b. ([a, _], [b, __]) => a < b ? -1 : 1, becomes ([a], [b]) => a - b,

  • The function extracting the word can be pair => pair[1], or ([, word]) => word, rather than ([_, word]) => word,

  • Why store the result in parsed. Just pass it on to the handling function. In this case the console.

Scope clutter

Keep the Ramba functions associated with the object so you don't end up with name clashes, and it makes it clearer what is doing what. (see example)

Example

const lyrics = {"99": [0, 7],"bottles": [1, 8], "of": [2, 9], "beer": [3, 10], "on": [4], "the": [5], "wall": [6]};

const log = console.log;
const song = R.join(' ');
const position = ([a], [b]) => a - b;
const word = ([,word]) => word;
const swapPair = ([word, positions]) => R.map(pos=> [pos, word], positions);

log(
  song(
    R.map(
      word, R.sort(
        position, R.unnest(R.map(
          swapPair, R.toPairs(lyrics)
        ))
      )
    )
  )
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

\$\endgroup\$

Your Answer

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

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