Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable the parser's zero-based to one-based arrays transform #782

Closed
jean-emmanuel opened this issue Jan 24, 2017 · 11 comments
Closed

Disable the parser's zero-based to one-based arrays transform #782

jean-emmanuel opened this issue Jan 24, 2017 · 11 comments
Labels

Comments

@jean-emmanuel
Copy link
Contributor

Hi, thanks for the great library !

Is there a way to switch from one-based arrays to zero based array in math's parser ?

@josdejong
Copy link
Owner

There is no configuration option for this but you could achieve so by overriding the set of functions that the expression parser uses math.expression.transform with the plain JS functions math:

// see the one-based behavior of the expression parser
console.log(math.eval('A[1]', {A: [1,2,3]}))   // 1

// see what functions have transforms
console.log(Object.keys(math.expression.transform))
// ["concat", "filter", "forEach", "index", "map", "max", "mean", "min", "range", "subset"]

// replace the object with `transformed` functions for an empty one
math.expression.transform = Object.create(math)

// the expression parser now has zero-based behavior:
console.log(math.eval('A[1]', {A: [1,2,3]}))   // 2

One caveat is that when you would import a new function after this change and this function comes with it's own transform, it will be added to math.expression.transform, so after an import you have to replace the transform object again.

@jean-emmanuel
Copy link
Contributor Author

jean-emmanuel commented Jan 24, 2017 via email

@josdejong
Copy link
Owner

👍 you're welcome

@jean-emmanuel
Copy link
Contributor Author

Is this still supposed to be true ? Seems like the trick isn't working anymore.

@josdejong
Copy link
Owner

josdejong commented Jan 3, 2018

Good point, there have been some internal refactorings. To achieve the same in the latest versions of mathjs, you can do the following:

// see the one-based behavior of the expression parser
console.log(math.eval('A[1]', {A: [1,2,3]}))   // 1

// see what functions have transforms
console.log(Object.keys(math.expression.transform))
// ["concat", "filter", "forEach", "index", "map", "max", "mean", "min", "range", "subset"]

// replace the object containing regular and transformed functions for an object with
// just regular functions. If needed , you can restore orginal behavior afterwards by 
// merging the functions in math.expression.transform again 
// in math.expression.mathWithTransform
math.expression.mathWithTransform = Object.assign({}, math)

// the expression parser now has zero-based behavior:
console.log(math.eval('A[1]', {A: [1,2,3]}))   // 2

@jean-emmanuel
Copy link
Contributor Author

Awesome, thank you !

@WesleyKapow
Copy link

@josdejong :'( Looks like this trick is once again no longer working? Got an update?

@josdejong
Copy link
Owner

Ah, yes indeed that doesn't work anymore since v6 I think. I will see if there is another workaround.

@josdejong
Copy link
Owner

josdejong commented Nov 20, 2019

@Wes-R this should be easier now in v6, however, I noticed that IndexNode currently uses a hard-coded, one-based instance of the index function. I've addressed this in b9175a1 (not yet published).

After this fix is published, it's simply a matter of cherry picking which functions you want to import, in your case that is all functions except transforms:

import { create, all } from 'mathjs'

// default, one-based indices:
const math = create(all)
console.log(math.evaluate('A[1]', { A: [1, 2, 3] })) // 1


// filter transform functions out of the imports:
const allButTransforms = {}
Object.keys(all)
  .filter(key => !key.endsWith('Transform'))
  .forEach(key => {
    allButTransforms[key] = all[key]
  })
// Alternatively using lodash:
//   const allButTransforms = pickBy(all, (value, key) => !key.endsWith('Transform'))

// custom zero-based indices:
const mathWithoutTransforms = create(allButTransforms)
console.log(mathWithoutTransforms.evaluate('A[1]', { A: [1, 2, 3] })) // 2

I will let you know as soon as this fix is published.

@josdejong
Copy link
Owner

Ok should be fixed now in mathjs@6.2.5, can you give it a try Wesley?

@WesleyKapow
Copy link

Success! TY!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants