Merge object Ramda - javascript

I am trying to perform um compare merge com ramda of the following values:
const data1 = {"crypto1":"BTCUSDT","crypto2":"ADABTC","crypto3":"ETHUPUSDT"};
const data2 = [
{"symbol":"ETHBTC","baseAsset":"ETH","status":"TRADING","id":1},
{"symbol":"BTCUSDT","baseAsset":"LTC","status":"TRADING","id":2},
{"symbol":"ETHUPUSDT","baseAsset":"BNB","status":"TRADING","id":3},
{"symbol":"NEOBTC","baseAsset":"NEO","status":"TRADING","id":4},
{"symbol":"ADABTC","baseAsset":"QTUM","status":"TRADING","id":5},
{"symbol":"EOSETH","baseAsset":"EOS","status":"TRADING","id":6}
];
What I need is to do a search for data1 (crypto) and match with data2, the expected result is:
result = [
{"symbol":"BTCUSDT","baseAsset":"LTC","status":"TRADING","id":1},
{"symbol":"ADABTC","baseAsset":"QTUM","status":"TRADING","id":2},
{"symbol":"ETHUPUSDT","baseAsset":"BNB","status":"TRADING","id":3}
]
It should be noted that the id must change according to the order of the data in the data1 variable
Thanking the support with some recommendation on how I should do it.

Use R.indexBy to create a dictionary of { [symbol]: object }, and then pick the items from the dictionary using R.props, after converting the keys (data1) to an array using R.values:
const { curry, pipe, indexBy, prop, props, values } = R;
const fn = curry((keys, data) => pipe(
indexBy(prop('symbol')), // index the values by the symbol
props(values(keys)) // convert the keys to an array and get them from the dictionary
)(data));
const data1 = {"crypto1":"BTCUSDT","crypto2":"ADABTC","crypto3":"ETHUPUSDT"};
const data2 = [{"symbol":"ETHBTC","baseAsset":"ETH","status":"TRADING","id":1},{"symbol":"BTCUSDT","baseAsset":"LTC","status":"TRADING","id":2},{"symbol":"ETHUPUSDT","baseAsset":"BNB","status":"TRADING","id":3},{"symbol":"NEOBTC","baseAsset":"NEO","status":"TRADING","id":4},{"symbol":"ADABTC","baseAsset":"QTUM","status":"TRADING","id":5},{"symbol":"EOSETH","baseAsset":"EOS","status":"TRADING","id":6}];
const result = fn(data1, data2);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

A very simple approach would be to :
map over the values from data1 - use R.values
find the object containing that as value against 'symbol' from 'data2' - use R.find and R.propEq
add indices accordingly - use R.addIndex
const R = require('ramda');
const result = R.addIndex(R.map)((k, idx) => ({
...R.find(R.propEq('symbol', k))(data2),
id: idx+1
}))(R.values(data1));
console.log(result);

Related

Remove duplicate String(Ignore Case) from list in angular 8 using lodash

I have a list of String with duplicate entries , So i want to remove them irrespective of Case
let duplicates = ['Hello', 'Hi', 'hello'];
let uniques = _.methodName(duplicates);
// output should be
['hello','Hi'] OR ['Hello','Hi']
You can use _.uniqWith() with a callback as following:
let duplicates = ['Hello', 'Hi', 'hello'];
let uniques = _.uniqWith(duplicates, (a,b) => a.toLowerCase() === b.toLowerCase())
console.log(uniques);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
One solution that avoids the need for a dependancy like lodash would be the following "vanilla js" approach:
let duplicates = ['Hello', 'Hi', 'hello'];
/* Pluck the values of the object mapping to an array */
let uniques = Object.values(
/* "Reduce" input array to an object mapping */
duplicates.reduce((obj, str) =>
/* Insert str value into obj mapping with lower case key */
({ ...obj, [str.toLowerCase()] : str }), {})
);
console.log(uniques)
Here an object mapping case insenstive keys to case sensitive values is built via Array#reduce. This mapping ensures that unique values are obtained irrespective of case. The Object#values method is then used to transform that mapping to the required uniques array.
Update
If Object#values is not available in your browser, you can use the following solution:
let duplicates = ['Hello', 'Hi', 'hello'];
let mapping = duplicates.reduce((obj, str) =>
({ ...obj, [str.toLowerCase()] : str }), {})
let uniques = Object.keys(mapping).map(k => mapping[k])
console.log(uniques)
Hope that helps!
It's very simple with _.uniq and _.map
Here is an exmaple:
let uniqueData = _.uniq(_.map(duplicates, (d) => d.toLowerCase()));
You can use _.uniqBy() with _.toLower() as iteratee:
const duplicates = ['Hello', 'Hi', 'hello'];
const result = _.uniqBy(duplicates, _.toLower);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
You can use uniqBy methods
_.uniqBy(data, function (e) {
return e.id;
});

Split an array into small arrays based on text in values

I have big array, which looks like this example:
let array = ['aa-we', 'aa-we__qq', 'aa-we__qw', 'gsPlsOdd', 'bc-po-lp', 'bc-po-lp--ps', 'de', 'de__io', 'de__sl', 'de--xz', 'ccsDdd'];
i want split this array into small arrays by values:
let array = [
['aa-we', 'aa-we__qq', 'aa-we__qw'],
['bc-po-lp', 'bc-po-lp--ps'],
['de', 'de__io', 'de__sl', 'de--xz']
]
// and camelcase strings should be removed
Values in array have syntax like BEM selectors, so if the prefix of different strings is the same, they should be wrapped in a single array.
How can i do this, if possible, without additional libraries?
Thanks for the help or tips!
console.clear()
let data = [
"aa-we",
"aa-we__qq",
"aa-we__qw",
"gsPlsOdd",
"bc-po-lp",
"bc-po-lp--ps",
"de",
"de__io",
"de__sl",
"de--xz",
"ccsDdd",
];
resultO = data.reduce((acc, val, idx) => {
if (val.match(/[A-Z]/)) {return acc;}
const sel = val.replace(/^(.*)(__|--).*$/g, "$1");
acc[sel] = acc[sel] || [];
acc[sel].push(val)
return acc;
}, {})
resultA = Object.values(resultO)
console.log(resultA)
I'd do something like this and then filter out what you don't want.
let array = ['aa-we', 'aa-we__qq', 'aa-we__qw', 'gsPlsOdd', 'bc-po-lp', 'bc-po-lp--ps', 'de', 'de__io', 'de__sl', 'de--xz', 'ccsDdd'];
array = array.filter((a) => !a.match(/[A-Z]/))
let result = groupBy(array, (str)=> str.split(/[-_]/)[0])
console.log(Object.values(result))
function groupBy(arr, condition) {
return arr.reduce((result, current) => {
const key = condition(current);
(result[key] || (result[key] = [])).push(current)
return result
}, {})
}
The algorithm can be as follows:
Create Map<Prefix,ValuesArray>
For each element in array:
Get it's prefix, e.g. "ab", skip element if invalid (e.g. no prefix exist or camel case)
Add to corresponding hashed bucket
Join values from Map into one array
JS has all the primitives to implement this, just take a look at Map/Object for hashing and Array (map/filter/reduce) for processing.

Lodash how to assign specific property of object during comparing two collections of different objects

I have one question. Is there any function in lodash library which is going to provide me the method for comparing each object in both collections by specific property and if the condition is fulfilled then creating another object?
example:
a) [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}....{}]
b) [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}...{}]
result:[{a:3,b:'dfe',c:'gty',d:'ghr'}]
I would like to compare these two collections by 'a' parameter and if a parameter is matched then assign parameter 'd' to object from the collection a). I have read something about differenceWith or intersection, but I am not sure if it may work, or maybe there are better functions to do this. Thanks in advance!
Create a Map of the items in array2 by their keys. Iterate array1 with Array.filter(), and remove all items that their a property is not found in the Map. Use Array.map() to combine the remaining items with d property of their counterpart in the Map:
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
// create a Map of array2 items by the a property
const array2Map = new Map(array2.map((o) => [o.a, o]));
const result = array1
// filter out all items that don't have matching item in the Map
.filter(o => array2Map.has(o.a))
// map the items, and add the d property from the item in the Map
.map(o => ({
...o,
d: array2Map.get(o.a).d
}));
console.log(result);
1) Native way: doing array map and comparing inside map loop with assigning objects.
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
const result = array1.map(obj1 => {
const obj2 = array2.find(obj => obj.a === obj1.a);
if (obj2) return Object.assign({}, obj1, {d: obj2.d});
}).filter(value => value);
console.log(result);
2) Lodash way: same as in example 1 but using only lodash methods
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
const result = _.compact(
_.map(array1, obj1 => {
const obj2 = _.find(array2, _.matchesProperty('a', obj1.a));
if (obj2) return _.assign({}, obj1, _.pick(obj2, ['d']));
})
);
console.log(result);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
P.S. Try to avoid lodash, underscore and etc stuff as much as possible. JS, ES are rich enough.

JavaScript find "newest" version of a string

This is probably something really easy, but I can't think of any good solution here:
I have an array of strings:
let array = ['House1', 'House2', 'House3', 'Block1', 'Block2', 'BlockSpecial1'];
In time this array will change, but at any point I want to able to reduce that array to just the "newest" versions of the strings (based on the ending numbers, they may become 2- or 3-digit at some point), so what I want in the end would be:
['House3', 'Block2', 'BlockSpecial1']
Reduce the array to an object with the string as key, and the version as value. To get the string and version, you can use String.match(), and array destructuring. Then use Object.entries(), and Array.map() to combine it back to strings:
const array = ['House1', 'House2', 'House3', 'Block1', 'Block2', 'BlockSpecial1'];
const result = Object.entries(array.reduce((r, s) => {
const [, str, version] = s.match(/([A-Za-z]+)(\d+)/);
r[str] = (r[str] || 0) > version ? r[str] : version; // or r[str] = version if the versions are always in the right order
return r;
}, Object.create(null)))
.map(([k, v]) => k + v);
console.log(result);
You can do this actually very cleanly by creating a Map.
const array = ['House1', 'House2', 'House3', 'Block1', 'Block2', 'BlockSpecial1'];
const re = /^([^]+?)(\d+)$/;
const result = [...new Map(array.map(s => re.exec(s).slice(1)))]
.map(a => a.join(""));
console.log(result);
Here's the rundown...
In a .map() over the original array, divide each string between its text and number using a regex, and return an array that has only the captured parts.
Have the .map() result become the argument to the Map constructor. This creates the map with each first member of the sub array as each key, and the second as the value.
Because a Map must have unique keys, you only get the last key produced for each redundant key, which will also have the highest number.
Then convert that map to its remaining key/value entries, and join them back into a string.
Here's the same code from above, but breaking it into parts so that we can log each step.
const array = ['House1', 'House2', 'House3', 'Block1', 'Block2', 'BlockSpecial1'];
const re = /^([^]+?)(\d+)$/;
const keysVals = array.map(s => re.exec(s).slice(1));
console.log("original split:", keysVals);
const m = new Map(keysVals);
const mapKeysVals = [...m];
console.log("mapped keys vals", mapKeysVals);
const result = mapKeysVals.map(a => a.join(""));
console.log("result", result);
let tmp, name;
let array = ['House1', 'House2', 'House3', 'Block1', 'Block2', 'BlockSpecial1'];
let newest = array.sort((a, b) => b.match(/\d+$/)[0] - a.match(/\d+$/)[0]).sort().reverse()
.reduce((newArr, item) => (name = item.match(/.+[^\d]+/)[0], name != tmp && (newArr.push(item), tmp = name), newArr), []);
console.log(newest) //[ 'House3', 'BlockSpecial1', 'Block2' ]

Javascript create array of objects dynamically

I have a JSON response i.e.
[{"name":"title","value":"STEP-01","translation":"STEP-01"},{"name":"meta_description","value":"","translation":"meta desc"}, ......]
from this I want to create an array of objects dynamically so that I get name as key and translation as value
like
data.en = {
title : 'STEP-01',
meta-description : meta desc
}
I have tried this but it creates an array
jsonObj = []
$.each(result, function (index, value) {
lang_array = {};
lang_array[value.name] = value.translation;
jsonObj.push(lang_array);
})
According to your example you are trying to create a JS object, and not an array.
Option 1: Use Array#reduce to collect the name and translation of each object to a new object:
const data = [{"name":"title","value":"STEP-01","translation":"STEP-01"},{"name":"meta_description","value":"","translation":"meta desc"}];
const result = data.reduce((r, { name, translation }) => {
r[name] = translation;
return r;
}, {});
console.log(result);
Option 2: Use a Array#map to create a collection of objects with the properties and the values, and combine them to a single object using Object#assign and spread:
const data = [{"name":"title","value":"STEP-01","translation":"STEP-01"},{"name":"meta_description","value":"","translation":"meta desc"}];
const result = Object.assign(...data.map(({ name, translation }) => ({ [name]: translation })));
console.log(result);

Categories

Resources