r-lib / fastmap

Fast map implementation for R
https://r-lib.github.io/fastmap/
Other
133 stars 7 forks source link

Utilities for fastmaps #25

Open stla opened 1 year ago

stla commented 1 year ago

Hello,

Haskell has very nice functions for hash maps.

For example:

getWithDefault <- function(map, key, default) {
  if(map$has(key)) {
    return(map$get(key))
  } else {
    return(default)
  }
}
map <- function(fastmap, f) {
  for(k in fastmap$keys()) {
    fastmap$set(k, f(fastmap$get(k)))
  }
}

And many interesting other ones. Do you intend to include such functions in the package? I can help if you want.

wch commented 1 year ago

I don't think that a getWithDefault() is necessary, since the get() method already has a missing parameter.

The map() method is interesting. In the rough version you've shown, it modifies the items in the fastmap in place, which seems a bit strange to me. Is that what the Haskell version does? (I'm not familiar with Haskell syntax.) I'd expect it to return a new object.

I could imagine some new methods being useful. There are things I like from purrr (but adapted for maps), the JavaScript lodash library, and Python dicts. For example:

I don't currently have time to sit down and think rigorously about which methods would be useful. If you have real-world use cases in mind, that would be helpful.

stla commented 1 year ago

No, Haskell does not modify in place.

I'm currently trying to translate a Haskell code to R which involves a map from the integers (encoded as characters with R) to the rational numbers (using gmp in R). Such a map is used to represent a cyclotomic number. This is my "real-world" use case :-) I've just started so far but I needed map and filter.

stla commented 1 year ago

There's also union and unionWith in Haskell. The unionWith function takes two maps and a binary function, it returns the map obtained by taking the union of the two input maps and by applying the input function to the two values corresponding to a common key.

unionWith <- function(f, mp1, mp2) {
  keys1 <- mp1$keys()
  keys2 <- mp2$keys()
  commonKeys <- intersect(keys1, keys2)
  mp <- fastmap()
  for(k in commonKeys) {
    mp$set(k, f(mp1$get(k), mp2$get(k)))
  }
  for(k in setdiff(keys1, commonKeys)) {
    mp$set(k, mp1$get(k))
  }
  for(k in setdiff(keys2, commonKeys)) {
    mp$set(k, mp2$get(k))
  }
  mp
}
stla commented 1 year ago

Also insertWith is very useful:

insertWith <- function(f, map, key, value) {
  if(map$has(key)) {
    map$set(key, f(value, map$get(key)))
  } else {
    map$set(key, value)
  }
  invisible(NULL)
}
stla commented 1 year ago

FYI, the merge function is very interesting because many other functions can be constructed from this one, such as unionWithKeys and intersectionWithKeys for example.

haskellMerge