Check if the value of key in an array of objects is same - Lodash - lodash

Want to check if either the values of all rows in the array of objects is same or the values of all columns in the array of objects is same. How do I efficiently do this with lodash?
[
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2}
]
In the above case all rows in the array of objects is same.

If I understood the constraints correctly, how about this?
var data = [
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2},
];
function allTheSame(data, key) {
return data.length && _.every(data, function (item) {
return item[key] === data[0][key];
});
}
console.log(_.any(['row', 'col'], function (key) {
return allTheSame(data, key);
}));
Note that _.every and _.any both bail out early, so this should be about as efficient as possible.
Also note that allTheSame returns false if there are no elements in the array. You could switch to return data.length === 0 || _.every(... instead if you want an empty list to be considered "all the same."

The tricky part is trying to check if both column or row values are the same, in the same iteration with lodash. However, that shouldn't be necessary unless your are dealing with an unspeakable amount of data. Assuming that is not the case, here's simple, linear approach:
function isRowOrColSame(data) {
var row = _.every(data, {'row': data[0].row})
var col = _.every(data, {'col': data[0].col})
return (row || col)
}
var data = [
{row: 0, col: 4},
{row: 0, col: 1},
{row: 0, col: 2}
]
console.log(isRowOrColSame(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
If you need an explanation as to what's going on with the every function, let me know. I hope that helps!

Related

Filtering an array from another array in vue

This might be something really simple, but I just can't figure it out. What I'm trying to do is take 2 arrays and filter out what I don't need and only
return the one array.
So what I have right now is this
let array1 = [1, 2, 3];
let array2 = [1, 2, 3, 4, 5, 6];
and what I would like is to return array 2 with only the items that doesn't show up in array1 so that would be 4, 5,6.
This is what I have so far
return array1.forEach(a => {
array2.filter(aa => aa !== a)
});
and that doesn't return anything
let array1 = [1, 2, 3];
let array2 = [1, 2, 3, 4, 5, 6];
let array3 = array2.filter(i => !array1.includes(i));
console.log(array3)
This might help to solve your problem.
let array1 = [1, 2, 3]
let array2 = [1, 2, 3, 4, 5, 6]
function returnList(arOne,arTwo){
return arTwo.filter(a => !arOne.includes(a))
}
let response = returnList(array1 ,array2 );

How to group by a key and sum other keys with Ramda?

Suppose I have an array of objects like this:
[
{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45},
{'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10},
{'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5},
{'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}
]
I would like to group by the first property and sum the values of the other properties, resulting in an array like this:
[
{'prop_1': 'key_1', 'prop_2': 79, 'prop_3': 55},
{'prop_1': 'key_2', 'prop_2': 16, 'prop_3': 12}
]
What is the correct way to do this using Ramda?
I have attempted to use the following:
R.pipe(
R.groupBy(R.prop('prop_1')),
R.values,
R.reduce(R.mergeWith(R.add), {})
)
But this sums also the value of 'prop_1'.
You'll need to map the groups, and then reduce each group. Check the values of the currently merged keys. If the value is a Number add the values. If not just return the 1st value:
const { pipe, groupBy, prop, values, map, reduce, mergeWith, ifElse, is, add, identity } = R
const fn = pipe(
groupBy(prop('prop_1')),
values,
map(reduce(
mergeWith(ifElse(is(Number), add, identity)),
{}
))
)
const data = [{"prop_1":"key_1","prop_2":23,"prop_3":45},{"prop_1":"key_1","prop_2":56,"prop_3":10},{"prop_1":"key_2","prop_2":10,"prop_3":5},{"prop_1":"key_2","prop_2":6,"prop_3":7}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
If and only if you know the keys in advance, you could opt for something "simpler" (of course YMMV):
reduceBy takes a function similar to Array#reduce
Use prop('prop_1') as a "group by" clause
(It should be relatively straightforward to extract the values out of the object to get the final array.)
console.log(
reduceBy
( (acc, obj) =>
({ prop_1: obj.prop_1
, prop_2: acc.prop_2 + obj.prop_2
, prop_3: acc.prop_3 + obj.prop_3
})
// acc initial value
, { prop_1: ''
, prop_2: 0
, prop_3: 0
}
// group by clause
, prop('prop_1')
, data
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.min.js"></script>
<script>const {reduceBy, prop} = R;</script>
<script>
const data = [{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45}, {'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10}, {'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5}, {'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}];
</script>
This answer is not as simple as that from Ori Drori. And I'm not sure whether that's a good thing. This seems to more closely fit the requirements, especially if "and sum the values of the other properties" is a simplification of actual requirements. This tries to keep the key property and then combine the others based on your function
const data = [
{'prop_1': 'key_1', 'prop_2': 23, 'prop_3': 45},
{'prop_1': 'key_1', 'prop_2': 56, 'prop_3': 10},
{'prop_1': 'key_2', 'prop_2': 10, 'prop_3': 5},
{'prop_1': 'key_2', 'prop_2': 6, 'prop_3': 7}
]
const transform = (key, combine) => pipe (
groupBy (prop (key)),
map (map (omit ([key]))),
map (combine),
toPairs,
map (([key, obj]) => ({prop_1: key, ...obj}))
)
console .log (
transform ('prop_1', reduce(mergeWith (add), {})) (data)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {pipe, groupBy, prop, map, omit, reduce, mergeWith, add, toPairs, lift, merge, head, objOf, last} = R </script>
If you have a fetish for point-free code that last line could be written as
map (lift (merge) (pipe (head, objOf(key)), last))
But as we are already making points of key and obj, I see no reason. Yes, we could change that, but I think it would become pretty ugly code.
There might well be something to be said for a more reduce-like version, where instead of passing such a combine function, we pass something that combines two values as well as a way to get the initial value. That's left as an exercise for later.

how to use lodash to sum data with the same key?

I have data like this:
var data = [
{2: 1, 6: 1},
{2: 2},
{1: 3, 6: 2},
];
(the "2" is like a key and "1" means "count")
and I want to output like this:
output = [
{2: 3, 6: 3, 1: 3},
];
is there a way to archive this by using lodash?
Use _.mergeWith() with spread to merge all keys and sum their values:
const data = [{2: 1, 6: 1}, {2: 2}, {1: 3, 6: 2}];
const result = _.mergeWith({}, ...data, (objValue, srcValue) =>
_.isNumber(objValue) ? objValue + srcValue : srcValue);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Accumulator not reset between 2 consecutive calls to R.reduce in a R.pipe

Considering this code, using Ramda 0.21.0:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
)
console.log(foo({ a: 1, b: 2})) // { a: 2, b: 3 }
console.log(foo({ c: 3, d: 4})) // { a: 2, b: 3, c: 4, d: 5 }
Why does the second call to foo display { a: 2, b: 3, c: 4, d: 5 } instead of { c: 4, d: 5 }?
Is there some kind of memoization going on? I would expect the initial value of acc to be reset to {} each time foo is applied.
This answer mostly expands on the comments by #iofjuupasli
The problem is the mutation of the accumulator object. You create one in the definition of foo which is reused on every call, and then you update it in iteratee (horrible name, IMHO. Call it bar or something. :-) ). There are several ways you could fix this. One might be to make sure that you pass a new accumulator on each call to foo:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
list => R.reduce(iteratee, {}, list)
)
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
This works, but feels unsatisfying. Perhaps more helpful would be to avoid mutating the accumulator object on each pass. assoc will create a new object that reuses as much of the previous one as possible:
var iteratee = (acc, [k, v]) => R.assoc(k, v + 1, acc)
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
This seems cleaner. But in fact Ramda has a much simpler solution. The map function treats objects as functors to be mapped over. Combining this with inc, which simply increments a value, we can just do this:
var foo = R.map(R.inc);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
And that feels really clean!

Swift: for-in with two values

I started learning C some weeks ago and today I started learning Swift. The code is the following:
import Foundation
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
var largest = 0;
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
}
}
}
println(largest);
Why do I need kind in the for-in thingy? For "Prime", "Square", ..., right? Can I work with that somehow, too?
“Add another variable to keep track of which kind of number was the largest, as well as what that largest number was.”
How do I build that in?
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind)");
That's my solution at the moment. However, the output is
The number 25 is from the type Optional("Square")
How do I get rid of the 'Optional("")? I just want the word Square. I tried removing the question mark (var largestKind: String?; to var largestKind: String;) but I get an error doing that.
For those who have the same question, this is another solution I've found. var largestKind is still optional because of String? but the exclamation mark at the end \(largestKind!) makes it possible to access the value without having that optional stuff around the actual content.
import Foundation
var largest = 0;
var largestKind: String?;
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 8, 16, 25],
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number;
largestKind = kind;
}
}
}
println("The number \(largest) is from the type \(largestKind!).");