4

I'm trying to get my head around using CoffeeScript comprehensions as efficiently as possible. I think I have basic mapping down -- turning one list into another -- but searching still seems verbose to me.

Say I have a map of items to shops:

shopMap:
  toyStore: ["games", "puzzles"]
  bookStore: ["novels", "picture books"]

and, given an item, I want to find out which shop it's in. What's the best way of doing that in CoffeeScript?

Here's how I could do in in JavaScript:

var shop = findShop(item);

function findShop(item) {
   for (shop in shopMap)
      itemList = shopMap[shop]
      for (i = 0, ii = itemList.length; i<ii; i++) {
         if (itemList[i] === item) {
            return shop;
         }
      }
  }
}

I used a function to allow it to quickly break out of the loops with the return statement, instead of using breaks, but the function is kind of fugly as this is only being used once.

So is there a shorter CS equivalent preferably one that doesn't require creating a new function?

0

2 Answers 2

8

You can try this:

findShop = (item) ->
  for shop, items of shopMap
    return shop if item in items

If you really want to try with a list comprehension, this is equivalent:

findShop = (item) ->
  (shop for shop, items of shopMap when item in items)[0]

But i think the first one reads better (and also doesn't need to generate an intermediate array for the results). This would be a better approach IMO if you wanted to find all shops for a given item:

findShops = (item) ->
  shop for shop, items of shopMap when item in items
Sign up to request clarification or add additional context in comments.

Comments

1

If this is a common operation, you might be better off creating an intermediate data structure up front and doing the lookup directly.

shopMap =
  toyStore: ["games", "puzzles"]
  bookStore: ["novels", "picture books"]

categoryMap = {}
for k, v of shopMap
  for category in v
    categoryMap[category] = k

alert(categoryMap['puzzles'])

Demo

With this implementation you need to loop through the structure only once up front (plus possibly update it if shopMap changes). With yours and epidemian's answer, you have to loop every time you need to do this particular type of lookup. If you do this operation a lot, it could make a difference. On the other hand, if your shopMap is really large (like thousands of entries), then my implementation will take up more memory.

Depending upon how robust you want to make this, you might want to turn it into a Class and have any operations on it occur through the Class' interface. You'd need addCategory and deleteCategory methods as well as a getStoreFromCategory method, which is essentially what we are implementing above. This object-oriented approach would hide the internal data-structure/implementation so you could later alter the implementation to optimize for memory or speed.

3 Comments

This is a good solution, in that the cost of a lookup is reduced to only a property access. But it should be noted that going for this for a first implementation is probably a case of premature optimization, at least with no much more information and it might bite later on (e.g. we don't know if the shopMap can change, and in that case the categoryMap should be updated too). I'd say better go for a naive implementation first, and only if performance is poor and, after profiling, the shop lookup is found to be a performance drag, then a solution like this can be implemented :)
Thank you. Yes, that is probably premature optimisation at this stage, bug I will keep it in mind if I find that I am repeatedly using that operation. Thank you.
Yeah, I tend to build large CoffeeScript libraries and applications so I have a very object-oriented way of thinking. My first approach would be to hide the implementation behind a Class interface and I'd probably use epidemian's implementation at first. The advantage of starting with a Class is that your client code doesn't need to change if you optimize the implementation later. Of course putting this in a Class in the first place might be over-engineering depending upon your situation.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.