Ramda, test two objects with multiple predicates for props equality - ramda.js

I have two objects that have the same props. I created few predicates to test them based on business logic:
const eqId = eqProps('equipmentId');
const eqQuantity = eqProps('quantity');
const eqColor = eqProps('color');
Each predicate accepts (o1, o2) as parameters. I am looking for a nicer way to output single value based on all predicates passing... in other words:
predicates.every(predicate => predicate(o1, o2) === true)
but in a more ramda style. allPass almost works but it accepts only a single object.
I know I can do this with every but this question is to help me learn more how to compose functions.

[...] allPass almost works but it accepts only a single object
Perhaps I'm not understanding 100% but I don't think that is true. The documentation says:
The function returned is a curried function whose arity matches that of the highest-arity predicate.
So given eqProps('foo') returns a binary function then the function returned by allPass will also be a binary function:
const check = allPass([eqProps('lunch'), eqProps('at')]);
check({lunch: '🌯', at: '1pm'}, {lunch: '🌯', at: '2pm'});
//=> false
check({lunch: '🌯', at: '1pm'}, {lunch: '🌯', at: '1pm'});
//=> true
If you have a "blueprint" for what your objects should look like, then I find eqBy(whereEq) easier to the eyes.
eqBy is better illustrated with an example. Hopefully this needs no further explanation:
const streqi = eqBy(toLower); // case insensitive equality
streqi("Foo", "fOO");
//=> true
So going back to eqBy(whereEq):
const check = eqBy(whereEq({lunch: '🌯', at: '1pm'}))
check({lunch: '🌯', at: '1pm', name: 'john'}, {lunch: '🌯', at: '1pm', name: 'tom'});
//=> true
check({lunch: '🌯', at: '1pm', name: 'john'}, {lunch: '🌯', at: '2pm', name: 'tom'});
// ^ ^
//=> false

We need to nest R.allPass and R.all since it is a matrix-like problem
const a = { suit: '♠︎', rank: '4' };
const b = { suit: '♠︎', rank: '9' };
const isSpade = R.propEq('suit', '♠︎');
const isCard = R.has('suit');
const compareWith = R.pipe(
R.allPass,
R.all,
R.unapply,
);
const isASpadeCard = compareWith([isSpade, isCard])
console.log(
isASpadeCard(a, b),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

Related

Typescript Record item count

Is it possible to find the count of items in a Typescript record?
For example something like
const testRecord: Record<string, string> = {
'one': 'value1',
'two': 'value2'
};
var length = testRecord.length;
// looking for length to be 2 but is undefined as there is no length property
For reference: https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt
I've just found this answer here for the length of a javascript object which seems to work just fine:
Length of a JavaScript object
My implementation to answer the example above was:
const testRecord: Record<string, string> = {
'one': 'value1',
'two': 'value2'
};
var length: Object.keys(testRecord).length;
// length equals 2
However please let me know if there is a better, more specific "Record" way to do this?
Maybe it's not what you wanted, but there is a Map type that has size property.
You can use it like this:
let m = new Map<string, any>();
m.set('a', 1)
let one = m.get('a');
console.log('a value is: ' + one + '; size of the map is: ' + m.size);
Map doesn't work exactly as Object does, so take a look at differences in behaviour first: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#objects_vs._maps

RamdaJS How to use R.find with R.or?

I'm still cutting my teeth on ramda and struggling with the basics.
I want to find the first object that has any of many properties set. So I'm trying to use a find with an or, but no matter how I construct it I cannot seem get it to work. repl.it
var xs = [{a: 1}, {b: 2}, {a: 3}];
R.find(R.or(R.prop('c'), R.prop('b')))(xs);
I was expecting this to evaluate to {b:2} but it keeps returning undefined. What am I doing wrong here?
In this case you will want R.either which takes two boolean producing functions, while R.or is just expecting two boolean values to compare (effectively a curried form of (a, b) => a || b).
I would not use prop to test whether an object has a property as it would return a false negative if a property is set to a falsy value. (Use has instead.) Also if you have more than two conditions you may want to consider using anyPass instead of either.
const findObject =
R.find(R.__, [
{a: 0},
{b: 1},
{c: 1}]);
// probably not the result you expected
findObject(
R.anyPass([
R.prop('a'),
R.prop('b')])); //=> {b: 1}
// most likely the result you expected
findObject(
R.anyPass([
R.has('a'),
R.has('b')])); //=> {a: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

Getting TypeError when recreating Lodash dropWhile() method in Javascript for an assignment

I get the error: "TypeError: arrayslice is not a function" in "const droppedArray = array.slice(n)" when my dropWhile() method calls the drop() method (below).
I'm confident that the dropWhile() method is correct - so no changes needed here.
I've tried problem solving the TypeError in the drop() method and reworking the code - but keep going in circles with this - can you tell me what is going wrong and how to fix this? I'm sure it's something simple...
drop: function(array,n){
if( n ===undefined){
var n = 1;
}
const droppedArray = array.slice(n);
return droppedArray;
},
dropWhile: function(array,predicate){
const dropNumber = array.findIndex(function(element, index){
return !predicate(element, index, array)
});
const dropArray = this.drop(dropNumber);
return dropArray;
}
I think you forgot to pass the array in your drop function:
const dropArray = drop(dropNumber); // <-- missing the array param
Should be:
const dropArray = drop(array, dropNumber);
What happens now is your drop function is trying to call slice on the index found by this row:
const dropNumber = array.findIndex(function(element, index){
Here is a fiddle to illustrate

Ramda: pass predicate equality argument last

I heve a static collection. And I want to check for any match by value each time, the value is changed.
Now I have:
var isOk = R.any(item => item.test(value), items);
What I want:
To store a function in other place and to call it like:
var isOk = checkMatch(value);
Any ideas? Thx.
UPDATE
I'm looking for solution in Ramda way. Something with changind call order of R.__
Wrap it in a closure that takes value.
var isOk = (value) => R.any(item => item.test(value), items);
var isOk_foobar = isOk('foobar');
I don't know for sure that your test items are regular expressions to use on
Strings, but if they are, you might try something like this:
const anyMatch = curry((regexes, val) => any(regex => test(regex, val), regexes))
const testFiles = anyMatch([/test\/(.)+\.js/i, /\.spec\.js/i])
testFiles('foo.js') //=> false
testFiles('test/foo.js') //=> true
testFiles('foo.spec.js') //=> true
And this looks clean to me, and very much in the spirit of Ramda. If you wanted to make it point-free, you could do this:
const anyMatch = useWith(flip(any), [identity, flip(test)])
But I find that much less readable. To me, point-free is a tool worth using when it improves readability, and to avoid when it doesn't.
You can see this in action on the Ramda REPL.

Queuing system for actionscript

Is there an actionscript library providing a queuing system?
This system would have to allow me to pass the object, the function I want to invoke on it and the arguments, something like:
Queue.push(Object, function_to_invoke, array_of_arguments)
Alternatively, is it possible to (de-)serialize a function call? How would I evaluate the 'function_to_invoke' with the given arguments?
Thanks in advance for your help.
There's no specific queue or stack type data structure available in ActionScript 3.0 but you may be able to find a library (CasaLib perhaps) that provides something along those lines.
The following snippet should work for you but you should be aware that since it references the function name by string, you won't get any helpful compiler errors if the reference is incorrect.
The example makes use of the rest parameter which allows you to specify an array of arbitrary length as the arguments for your method.
function test(... args):void
{
trace(args);
}
var queue:Array = [];
queue.push({target: this, func: "test", args: [1, 2, "hello world"] });
queue.push({target: this, func: "test", args: ["apple", "pear", "hello world"] });
for (var i:int = 0; i < queue.length; i ++)
{
var queued:Object = queue[i];
queued.target[queued.func].apply(null, queued.args);
}
Sure, that works similar to JavaScript
const name:String = 'addChild'
, container:Sprite = new Sprite()
, method:Function = container.hasOwnProperty(name) ? container[name] : null
, child:Sprite = new Sprite();
if (method)
method.apply(this, [child]);
So a query method could look like:
function queryFor(name:String, scope:*, args:Array = null):void
{
const method:Function = scope && name && scope.hasOwnProperty(name) ? scope[name] : null
if (method)
method.apply(this, args);
}