find all the string values and the corresponding keys - javascript

I am trying to find all the string values from the array of objects and then format the keys.
//it works for a single object and string
// need help to implement an array of Object and string
function getKeyByValue(object, value) {
return Object.keys(object).find((key) => object[key] === value);
}
const data = [
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}
];
const mapper = data.map((item) => {
const values = Object.values(item).filter((item) => typeof item === "string");
console.log(values);
// problem here;
//it's now taking a single object and a single string
// how can I take an array of objects and strings as parameters here
console.log(getKeyByValue(data[0], values[1]));
});
And finally output in this format
[
{fieldname: 'ContextName'},
{fieldName: 'PrimaryKey'},
{fieldName: 'BaseMasterTable'}
]

You can try this approach with Object.entries and map together. And flatMap to group all string data into a single array.
const data = [{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}];
const mapper = data.flatMap((item) => {
const result = Object.entries(item).filter(([key, value]) => typeof value === "string").map(([key, value]) => ({
fieldname: key
}));
return result
});
console.log(mapper)

Each object of array is iterated by .flatMap(). On each iteration the current object is converted into an array of pairs by Object.entries()
data.flatMap(obj => Object.entries(obj)
// [["AddressFlag", true], ["BaseMasterTable", "DIMCUSTOMER"], [...], ...]
Next, .flatMap() is used again, but this time as a filter. Since .flatMap() flattens it's returns by a level we can apply a ternary or if/else if/else statement with a empty array ([]) as the else or last part of a ternary. Doing so will cleanly return nothing (instead of the usual empty ("")). This technique is especially useful because you can return anything -- in the example, the condition is checking each pair second element (pair[1] which is originally the value) and if it's the given type (in the example is "string") the first element of the pair is returned as the value of an object (pair[0] which is originally the key). If it isn't the given type an empty array is returned.
data.flatMap(obj => Object.entries(obj).flatMap(pair =>
typeof pair[1] === "string" ? {"fieldName": pair[0]} : []))
// is "DIMCUSTOMER" a string ? return {"fieldName": "BaseMasterTable"} OR []
Details are commented in example
const data = [{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey"
}];
/**
* Return an array of objects of which each object has a commonly shared key
* and a value derived from the key of an object of a given array. The object
* itself is determined by the given type of it's value.
* #param {array<object>} array - An array of objects
* #param {string} type - The type a value of an object property to accept
* #param {string} [newKey = "fieldName"] - The name of the commonly shared
* key of each object in the returned array. If undefined it defaults
* to "fieldName".
* #returns {array<object>} - An array of objects (see description above)
*/
function keysByType(array, type, newKey = "fieldName") {
return array.flatMap(obj =>
Object.entries(obj).flatMap(pair =>
typeof pair[1] === type ? {
[newKey]: pair[0]
} : []));
}
console.log(keysByType(data, "string"));

You can use flatMap and Object.entries() for this. Pretty simple:
const data = [
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
},
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}
];
const result = data.flatMap(element => {
return Object.entries(element)
.filter(([,value]) => typeof value === "string")
.map(([key]) => ({fieldName: key}));
});
console.log(result)
This will duplicate keys, you can then filter if you need to.

This answer is almost the same approach as provided answers. Only difference is it is one loop less. I'm using flatMap here instead of filter & map. Something like this:-
const data = [{AddressFlag: true,BaseMasterTable: "DIMCUSTOMER",ContextName: "Kunden", DefaultOutputFormats: null, HouseHoldColumn: null, I18N: [], ID: 5, PrimaryKey: "CustomerKey", } ];
const result = data.flatMap(e=>Object.entries(e).flatMap(([fieldName,v])=>typeof v==='string' ? ({fieldName}) : []));
console.log(result);

Related

Ramda: How to remove keys in objects with null values, empty arrays and empty lists recursively? [duplicate]

This question already has answers here:
How do I implement using point-free recursion to remove null values in objects using Ramda?
(2 answers)
Closed 1 year ago.
Similar to Ramda: How to remove keys in objects with empty values? but I am looking for something that works recursively. This is so I can workaround a "feature" of AJV and JSON Schema where null !== undefined.
I started with this... which is to remove the nulls but does not work recursively
import R from 'ramda';
describe('filter null values', () => {
it('should filter out null values', () => {
const specimen = {
tasks: [
{ id: 'foo', blank: '', zero: 0, nool: null },
{ nool: null },
{ id: '', blank: null, zero: 0, nool: null },
],
useless: { nool: null },
uselessArray: [{ nool: null }],
nool: null,
};
const expectation = {
tasks: [
{ id: 'foo', blank: '', zero: 0 },
{ id: '', zero: 0 },
],
};
const removeNulls = R.reject(R.equals(null));
expect(removeNulls(specimen)).toEqual(expectation);
});
});
Map the passed item. If the value is an Object (or Array), recursively call removeNulls on the current value. After mapping the values, reject all undefined, null, or empty non string values (see R.isEmpty).
const { pipe, map, when, is, reject, ifElse, F, either, isEmpty, isNil } = R;
const removeNulls = pipe(
map(when(is(Object), v => removeNulls(v))),
reject(ifElse(is(String), F, either(isEmpty, isNil))),
);
const specimen = {"tasks":[{"id":"foo","blank":"","zero":0,"nool":null},{"nool":null},{"id":"","blank":null,"zero":0,"nool":null}],"useless":{"nool":null},"uselessArray":[{"nool":null}],"nool":null};
const result = removeNulls(specimen);
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" referrerpolicy="no-referrer"></script>

Based on type change object to nested array in javascript

How to change nested object to array object by type in javascript.
Based on object key value type if its array/string
change the object to array as shown below in javascript
var ob1 = {
"list": [
"service",
"finance",
"s1.jpg"
],
"info": [
"details",
"mail",
"s2.jpg"
]
}
var ob2 = {
key1: "v1",
key2: "v2"
}
var result1=this.modifyObject(ob1);
var result2=this.modifyObject(ob2);
function modifyObject(ob){
const { field, value, id, ...fields } = ob;
const rest = Object.entries(fields)
.map(([field, value], id) => ({ field, value, id }));
const result = [...rest];
return result;
}
Expected Output,
// object type value is array
[
{field: "list", value: ["service","finance"], image: "s1.jpg", id:0},
{field: "info", value: ["details","mail"], image: "s2.jpg", id:1}
]
// object type value is string
[
{field:"key1", value:"v1", id:0 },
{field:"key2", value:"v2", id:1 }
]
You can grab the entires of your input object using Object.entries() and map each [key, value] pair to a new object. You can determine what type of object you want to return by checking whether the second value in the [key, value] pair array is an array (ie: checking if the value is an array) by using Array.isArray(). If it is an array, you can set the value to be the array, and the image to be the last element (obtained by using .pop(), if you don't want to modify the original object you can use slice instead). Otherwise, if the element is not an array, you can return an object which has an id property. The id property is based on the index of the object from the mapping function.
See example below:
const ob1 = { "list": [ "service", "finance", "s1.jpg" ], "info": [ "details", "mail", "s2.jpg" ] }; const ob2 = { key1: "v1", key2: "v2" };
const modifyObject = obj =>
Object.entries(obj).map(([field, value], id) =>
Array.isArray(value) ? {field, value, image: value.pop()}
: {field, value, id}
);
const result1 = modifyObject(ob1);
const result2 = modifyObject(ob2);
console.log(result1);
console.log(result2);
Note that this id property is based on the ordering of how Object.entries() obtains the key-value pairs from your object, so it may differ in older browsers (the newest JS spec specifies the ordering of how the [key, value] pairs are obtained using Object.entries, but older browsers may not follow this)
You can use the function Array.prototype.entries along with the function Array.prototype.reduce to build the desired output.
let ob1 = { "list": [ "service", "finance", "s1.jpg" ], "info": [ "details", "mail", "s2.jpg" ]},
ob2 = { key1: "v1", key2: "v2"};
function modifyObject(obj) {
return Object.entries(obj).reduce((r, [field, value], id) => {
let [image] = Array.isArray(value) ? value.slice(-1) : [];
let v = Array.isArray(value) ? value.slice(0, value.length - 1) : value;
return r.concat(Object.assign({id, [field]: v}, image ? {image} : {}));
}, []);
}
console.log(modifyObject(ob1));
console.log(modifyObject(ob2));

Filter through plain object key-value pairs

I have a JS Object of the form stored in a variable keyData:
{type: "", label: "fname", title: "first name", …}
defaultvalue: ""
disabled: false
label: "fname"
readonly: false
required: "on"
title: "first name"
type: ""
__proto__: Object
I want to filter through these key-value pair and return a new object which contains the key-value pair with data available in them. For example, in this data, it should return title, required, and label only.
With that new filtered data, I want to map a react form with filtered keys as input types and filtered values as their value.
I am confused on how to solve this. I tried using Object.entries(keyData)
like this:
Object.entries(keyData).filter(x => console.log(x))
console.log(keyData)
on the console.log(keyData), it prints:
(2) ["type", ""]
(2) ["label", "fname"]
(2) ["title", "first name"]
(2) ["placeholder", ""]
(2) ["required", "on"]
(2) ["readonly", false]
(2) ["disabled", false]
I am unable to filter through this empty data further.
One option is to use reduce after you use Object.entries. You can then return an object only when the value is truthy.
const data = {
a: "foo",
b: false,
c: "bar",
d: null
};
const filtered = Object.entries(data).reduce((acc, [key, value]) => {
if (value) {
acc[key] = value;
}
return acc;
}, {});
console.log(filtered);
You need filter() and then reduce() to make it object
Object.entries(keyData).filter((key, value) => value).reduce((prev, curr) => {
prev[curr[0]] = curr[1];
return prev;
}, {});

Restructure Javascript Object by grouping and Cartesian product

I have some raw javascript returned from an api that looks like this:
{"Values":
[
{
"fieldValue": 1,
"fieldName": "A"
},
{
"fieldValue": 2,
"fieldName": "A"
},
{
"fieldValue": "FOO",
"fieldName": "B"
},
{
"fieldValue": "BAR",
"fieldName": "B"
}
]
}
I want to restructure it in a way that requires grouping of attributes, converting attributes to values and a Cartesian join that results in an array of objects that looks like this:
[{"A":1,"B":"FOO"},{"A":2,B:"FOO"},{"A":1,"B":"BAR"},{"A":2,"B":"BAR"}]
I've been looking at the loDash and loDash.product library that is helpful but doesn't quite fer me there. The _groupby gives me an object of arrays rather than an array of objects:
{object:
[fieldName:"A",fieldValue:1],[fieldName:"A",fieldValue:2],[fieldName:"B",fieldValue:1],[fieldName:"B",fieldValue:2]
}
First, create an object using the given data and collect the keys and their values.
{
A: [1, 2],
C: ["FOO", "BAR"]
}
Then, get the Cartesian product of this object.
The function getCartesian separates all key/value pairs and builds a new Cartesian product by iterating over the values, if an array with objects call getCartesian again, and builds new objects.
This works for nested objects as well.
The algorithm is pretty simple, because it takes any property with a value, not just an array or object, and keeps this value and iterates over all other properties, which are arrays or objects. This algorithm keeps the inner structure and takes only the primitive values as result value for the given structure.
At the beginning, it takes an object/array, gets all entries and iterates them using an array with an empty object.
An empty array temp is the new result.
For creating new elements, the accumulator r is iterated and new values are collected. This is the part where the first level of a Cartesian product is made.
For a deeper level, a value is checked as well as "if an object", then a recursive call is made and the new result is taken for the actual key.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
var data = { Values: [{ fieldValue: 1, fieldName: "A" }, { fieldValue: 2, fieldName: "A" }, { fieldValue: "FOO", fieldName: "C" }, { fieldValue: "BAR", fieldName: "C" }] },
temp = data.Values.reduce((r, { fieldName, fieldValue }) => {
(r[fieldName] = r[fieldName] || []).push(fieldValue);
return r;
}, {}),
cartesian = getCartesian(temp);
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }

javascript: Using lodash/fp flow to return objects

I am converting a _.chain group of functions to use _fp.flow, but am having some difficulty dealing with the way flow curries complex objects. I am trying to
Reduce an array of objects with some grouped function (e.g. countBy/sumBy) into a object/dictionary (e.g. { group1:10, group2:15... } )
Map it into an array of key/value pairs (e.g. [{column: 'group1', value: '10'}, ...])
Sort by some variable into asc/desc order
but right now the resulting object ends up being flattened into a long array. A sample of the code is below. The reducer function in the code below is working correctly and grouping the values as I intended, but then I think the currying between the each step and orderBy is flattening the object somehow (the desired object is formed correctly after _.each in the console.log.
I've put a sample of the code in the attached JSFiddle.
const inData = [{
target: 123,
groupby: 'a'
},...
}];
const colData = _.flow(
_.reduce(reducer, {}),
_.toPairs,
_.each(([value, column]) => {
console.log(value);
console.log(column);
const outObj = {
value: value,
column: column
}
console.log(outObj)
return (outObj);
}),
_.orderBy(['value'], [sortDir]),
// Have tried result with or without fromPairs
_.fromPairs
)(inData);
PS: I am using ES6 syntax and React in my main project, if that makes a difference.
https://jsfiddle.net/moc0L5ac/
You need to use map instead of each and also fix the order of [value, column] to [column, value]
const colData = _.flow(
_.reduce(reducer, {}),
_.toPairs,
_.map(([column, value]) => {
const outObj = {
value: value,
column: column
}
return outObj;
}),
_.orderBy(['value'], [sortDir])
)(inData);
To the best my understanding, this is what you're looking to accomplish
const inData =
[ { target: 123, groupby: 'a' },
{ target: -123, groupby: 'b' },
{ target: 123, groupby: 'a' },
{ target: -123, groupby: 'b' } ]
const colData = _.flow(
_.reduce((map, {target:v, groupby:k}) =>
Object.assign(map, { [k]: map[k] === undefined ? v : map[k] + v }), {}),
_.toPairs,
_.map(([column, value]) => ({ column, value }))
)
console.log(colData(inData));
// => [ { column: 'a', value: 246 },
// { column: 'b', value: -246 } ]

Categories

Resources