arrange array to become object array base on duplicate string - javascript

I have array and I want to arrange that to object array structure base on same string before dot, I want to create an object array structure to make it editable, so i can fill the value of each data on my array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"]
how can i arrange that to become object array structure
var arr = [ "data": {
"plmn": "",
"id": "",
"time": '',
"cell": {
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"earfcn": '',
"pci": '',
"celltiming": [
0,
1
],
"sinr": [
0,
1
]
},
"mac": ""
},
"time": '',
"deviceID": ""]
I want to create an object array so i can fill the value of each key

I've used the following:
Array.prototype.reduce(), accumulating over an empty object {},
A reference (ref) to the accumulator object,
String.prototype.split() to extract individual keys (substrings) from the current string in the array,
Iterating over the keys to progress along the key "chain",
a. If a key doesn't already exist in the accumulator object, create an object at that key, i.e. if (!ref[key]) ref[key] = {}
b. Continue to traverse the accumulator object by re-setting the reference (ref), i.e. ref = ref[key]
Move to the next string in the original array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
console.log(JSON.stringify(obj, null, "\t"));
This gets you most of the way. Now all you need to do is:
Traverse the object (first pass), replacing empty objects with empty strings, then
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
Traverse the object (second pass), checking when all of the keys of an object are numbers and all of the values are empty strings, and replacing this object with an array of the keys.
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
Complete solution: https://jsfiddle.net/s2attatz/1/
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
console.log(JSON.stringify(obj, null, "\t"));
/*
{
"data": {
"cell": {
"celltiming": [
0,
1
],
"earfcn": "",
"pci": "",
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"sinr": [
0,
1
]
},
"cells": {
"0": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"1": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"2": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"3": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
}
},
"id": "",
"mac": "",
"plmn": "",
"rssi": "",
"time": ""
},
"deviceID": "",
"time": ""
}
*/

Related

Convert keys from key value pair to capital case using javaScript

I am trying to convert the keys in JSON to the capital case using Javascript. I am successful to some extent. However, it is not creating the arrays in the correct way. It is inserting numbers before every object inside an array.
Input:
{
"id": "123",
"retweetCheck": {
"result": "OK",
"checks": [
{
"cId": "123"
},
{
"cId": "456"
}
]
},
"tweetCheck": {
"result": "OK",
"cId": "345",
"check": "Fail"
}
}
Code to convert the keys to capital case:
var responseContent = context.getVariable("response.content") || "";
responseContent = JSON.parse(responseContent) || "";
transformedCapitalizedObj = keysToCapitalCase(responseContent);
var finalResponseObj = {
Data: transformedCapitalizedObj
};
context.setVariable("response.content", JSON.stringify(finalResponseObj));
The function
function objEntries(obj) {
const keys = Object.keys(obj);
const keyValuePairs = keys.map(key => {
const value = obj[key];
return [key, value];
});
return keyValuePairs;
}
function keysToCapitalCase(objToProcess) {
if (!objToProcess || typeof objToProcess !== "object") return null;
var finalObj = {};
objToProcess = objEntries(objToProcess);
objToProcess.forEach(function (entry) {
var key = entry[0];
var value = entry[1];
key = key.charAt(0).toUpperCase() + key.slice(1);
if (typeof value == "object" || (value instanceof Array)) {
value = keysToCapitalCase(value);
}
finalObj[key] = value;
});
return finalObj;
}
The output I am getting currently is:
{
"Data":{
"RetweetCheck":{
"Checks":{
"0":{
"CId":"123"
},
"1":{
"CId":"456"
}
},
"Result":"OK"
},
"Id":"123",
"TweetCheck":{
"CId":"345",
"Check":"Fail",
"Result":"OK"
}
}
}
But ideally, the output should look like this:
{
"Data": {
"Id": "123",
"RetweetCheck": {
"Result": "OK",
"Checks": [
{
"CId": "123"
},
{
"CId": "456"
}
]
},
"TweetCheck": {
"Result": "OK",
"CId": "345",
"Check": "Fail"
}
}
}
It is basically inserting a serial number before each object inside an array instead of []. How this can be rectified. Any help will really do wonders.
When you call your function keysToCapitalCase(), first check if you have an array (with ES6, you can do this using Array.isArray()), and if you do, you can map the objects / inner arrays within that array to the result of recursively calling your keysToCapitalize function. Otherwise, if you get a standard object that isn't an array, you can perform your standard object mapping:
const obj = { "id": "123", "retweetCheck": { "result": "OK", "checks": [{ "cId": "123" }, { "cId": "456" } ] }, "tweetCheck": { "result": "OK", "cId": "345", "check": "Fail" } };
function keysToCapitalCase(objToProcess) {
if (!objToProcess || typeof objToProcess !== "object") return null;
if(Array.isArray(objToProcess)) {
return objToProcess.map(obj => keysToCapitalCase(obj));
}
var finalObj = {};
objToProcess = Object.entries(objToProcess); // if you can support it, `Object.entries()` does what `objEntries` does
objToProcess.forEach(function(entry) {
var key = entry[0];
var value = entry[1];
key = key.charAt(0).toUpperCase() + key.slice(1);
if (typeof value == "object") {
value = keysToCapitalCase(value);
}
finalObj[key] = value;
});
return finalObj;
}
var finalResponseObj = {Data: keysToCapitalCase(obj)};
console.log(finalResponseObj);
I would probably write the above method in a similar way, but instead using some inbuilt functions to make it a little more concise, such as .map() and Object.fromEntries():
const obj = { "id": "123", "retweetCheck": { "result": "OK", "checks": [{ "cId": "123" }, { "cId": "456" } ] }, "tweetCheck": { "result": "OK", "cId": "345", "check": "Fail" } };
const cap = str => str.charAt(0).toUpperCase() + str.slice(1);
const keysToCapitalCase = (objToProcess) => {
if (Object(objToProcess) !== objToProcess) return null;
return Array.isArray(objToProcess)
? objToProcess.map(obj => keysToCapitalCase(obj))
: Object.fromEntries(Object.entries(objToProcess).map(([key, val]) => [
cap(key), Object(val) === val ? keysToCapitalCase(val) : val
]));
}
const finalResponseObj = {Data: keysToCapitalCase(obj)};
console.log(finalResponseObj);
As indicated by the {} brackets, instead of the wanted [] brackets you are creating an empty object and not an Array.
To create an Array just change your var finalObj = {}; to var finalObj = [];
with an Array finalObj[key] = value will no longer work, you will now have to use finalObj.push(value)

Renaming object keys which are nested

I am accessing JSON which looks like this.
[
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
...
}
}, ...
And I am having trouble renaming the object keys which have the . in the name to an _. For example:
item.Type or selection.Type to item_Type or selection_Type.
This is what I am trying to use:
var json = jsonFromExampleAbove;
str = JSON.stringify(json);
str = str.selectionFile.replace(/\".\":/g, "\"_\":");
json = JSON.parse(str);
console.log(json);
I am getting a console log error. I think it is because the values I am trying to replace are nested, but not sure. I am still very much a beginner here.
Thank you.
I would be tempted to do it with a bit of recursion using Object.entries and Object.fromEntries
const input = [
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
}
}];
function replaceDots(obj){
return Object.fromEntries(Object.entries(obj).map( ([key,value]) => {
const newKey = key.replace(".","_");
return typeof value == "object"
? [newKey, replaceDots(value)]
: [newKey, value]
}));
}
const result = input.map(replaceDots);
console.log(result);
Your solution with a replaceAll on the stringified JSON could result in unwanted problems when a value contains a dot.
For renaming nested keys of an object you need go over the object recursively and assign the new keys while removing the old ones
// for ES6
function renameKey(obj) {
// loop over all keys
for (let k in obj) {
// apply recursively if value is an object
if (typeof obj[k] === "object" && obj[k] !== null)
renameKey(obj[k]);
// only replace keys of type String
if (typeof k === 'string' || k instanceof String) {
const newKey = k.replaceAll(".", "_");
// assign {newKey:value} to object and delete old key
delete Object.assign(obj, { [newKey]: obj[k] })[k];
}
}
return obj
}
You can use a recursive approach to replace the keys in the input object(s) with your desired result. There's no need to use JSON.stringify(), one can simply iterate through the objects.
We'll use searchValue to specify what we wish to search for and newvalue to specify the replacement, in this case they will be /./g and '_'.
let arr = [
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
}
}
]
function replaceKeys(obj, searchvalue, newvalue, newObj) {
if (!newObj) newObj = Array.isArray(obj) ? []: {};
for(let k in obj) {
let newKey = k.replace(searchvalue, newvalue);
if (typeof(obj[k]) === 'object') {
newObj[newKey] = Array.isArray(obj[k]) ? []: {};
replaceKeys(obj[k], searchvalue, newvalue, newObj[newKey])
} else {
newObj[newKey] = obj[k];
}
}
return newObj;
}
const result = replaceKeys(arr, /\./g, '_');
console.log('Result:', result);

How to select specific properties of object where aren't null in ES6?

I want to select specific object properties where they aren't null.
I want to select id and name of this object:
{
"description": "hello",
"title": "Update",
"id": "1",
"name": null
}
expected output:
{
"id": "1",
// no name because it's null
}
I tried to do that using this code:
const { title, description, ...newValues } = values;
console.log(newValues);
You can filter all null elements by converting them to an entries array and then back to an object:
const filteredNewValues = Object.fromEntries(Object.entries(newValues).filter(e => e[1]))
Browser-Support is limited. So use a polyfill if you need to use it in old browsers. See here.
Grab all keys with Object.keys and then using reduce to get the selected property only that is not null.
You can use condition either obj[curr] or obj[curr] !== null
const obj = {
description: "hello",
title: "Update",
id: "1",
name: null,
};
const selected = ["id", "name"];
const result = Object.keys(obj).reduce((acc, curr) => {
if (selected.includes(curr) && obj[curr]) {
acc[curr] = obj[curr];
}
return acc;
}, {});
console.log(result);
let data = {
"description": "hello",
"title": "Update",
"id": "1",
"name": null
}
let filteredData = data.name && data.id ? {id: data.id, name: data.name} : undefined
Okay, let's assume that you want to make it in a dynamic way.
/**
* Get wanted properties of an object
* #param object
* #param {string[]} keys
*/
function cloneObject(obj, keys) {
return keys
.filter(key => obj[key] !== null)
.reduce((newObj, key) => {
newObj[key] = obj[key];
return newObj;
}, {});
}
// here you have your wanted keys
let keys = ['id', 'name'];
let object = {
"description": "hello",
"title": "Update",
"id": "1",
"name": null
};
let newObject = cloneObject(object, keys);
You could create a simple function to extract only non-null passed keys.
var data = {
"description": null,
"title": "Update",
"id": "1",
"name": false
};
function get(data, keys)
{
return keys.reduce((acc, cur) => {
return {...acc, ...(data[cur] !== undefined && data[cur] !== null && {[cur]: data[cur]})}
}, {});
}
console.log(get(data, ["description", "title", "id", "name", "fake"]));

Convert an array to json object by javascript

I am stuck to solve this problem.
Convert an array below
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
to json Object
var expectedResult = {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
Which data structure and algorithm can I apply for it?
Thanks
You need to first split each element to convert to array
using reverse reduce method you can convert them to object.
And your last step is merge this objects.
Lodash.js merge method is an one way to merge them.
var input = ['animal/mammal/dog','animal/mammal/cat/tiger','animal/mammal/cat/lion', 'animal/mammal/elephant','animal/reptile', 'plant/sunflower']
var finalbyLodash={}
input.forEach(x=>{
const keys = x.split("/");
const result = keys.reverse().reduce((res, key) => ({[key]: res}), true);
finalbyLodash = _.merge({}, finalbyLodash, result);
});
console.log(finalbyLodash);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
To make the process more understandable, break the problem down into pieces.
The first step is convert each string into something we can use, converting this:
"animal/mammal/dog"
into this:
[ "animal", "mammal", "dog" ]
That's an array of property names needed to build the final object.
Two functions will accomplish this for you, String.prototype.split() to split the string into an array, and Array.prototype.map() to transform each of the array elements:
let splitIntoNames = input.map(str => str.split('/'));
The intermediate result is this:
[
[ "animal", "mammal", "dog" ],
[ "animal", "mammal", "cat", "tiger" ],
[ "animal", "mammal", "cat", "lion" ],
[ "animal", "mammal", "elephant" ],
[ "animal", "reptile" ],
[ "plant", "sunflower" ]
]
Next step is to iterate over each array, using Array.prototype.forEach() to add properties to the object. You could add properties to the object with a for loop, but let's do that with a recursive function addName():
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
The result:
result: {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
const input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/mammal/elephant",
"animal/reptile",
"plant/sunflower",
];
let splitIntoNames = input.map((str) => str.split("/"));
console.log("splitIntoNames:", JSON.stringify(splitIntoNames, null, 2));
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
console.log("result:", JSON.stringify(result, null, 2));
You can create a function that will slice every element from the array by "/" than you put the results into a variable and than just mount the Json. I mean something like that below:
window.onload = function() {
var expectedResult;
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
input.forEach(element => {
var data = element.split('/');
var dog = data[2] === 'dog' ? true : false
var tiger = data[2] === 'cat' && data[3] === 'tiger' ? true : false
var lion = data[2] === 'cat' && data[3] === 'lion' ? true : false
expectedResult = {
data[0]: {
data[1]: {
"dog": dog,
"cat": {
"tiger": tiger,
"lion": lion
}
}
}
}
})
}
Late to the party, here is my try. I'm implmenting recursive approach:
var input = ['animal/mammal/dog', 'animal/mammal/cat/tiger', 'animal/mammal/cat/lion', 'animal/mammal/elephant', 'animal/reptile', 'plant/sunflower'];
result = (buildObj = (array, Obj = {}) => {
array.forEach((val) => {
keys = val.split('/');
(nestedFn = (object) => {
outKey = keys.shift();
object[outKey] = object[outKey] || {};
if (keys.length == 0) object[outKey] = true;
if (keys.length > 0) nestedFn(object[outKey]);
})(Obj)
})
return Obj;
})(input);
console.log(result);
I try with array reduce, hope it help
let input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/elephant",
"animal/reptile",
"plant/sunflower",
];
let convertInput = (i = []) =>
i.reduce((prev, currItem = "") => {
let pointer = prev;
currItem.split("/").reduce((prevPre, currPre, preIdx, arrPre) => {
if (!pointer[currPre]) {
pointer[currPre] = preIdx === arrPre.length - 1 ? true : {};
}
pointer = pointer[currPre];
}, {});
return prev;
}, {});
console.log(JSON.stringify(convertInput(input), null, 4));

filter object by two nested values

I'm facing a problem with filter method. On my page there's an input to search matches by team names. Filter value is being stored to React state. Matches object looks like this:
[
{
"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": [
{
[...]
}
]
},
"teamRed": {
"id": 37,
"name": "nameForTeamRed",
"playerList": [
{
[...]
}
]
},
"localDate": "2020-01-01",
"localTime": "00:00:00",
"referee": null,
"commentator1": null,
"commentator2": null,
"streamer": null,
"stage": {
"id": 2,
"name": "GROUPSTAGE"
},
"onLive": true,
"finished": false
},
]
I tried tons of methods to filter matches by team name, for example:
let criteria = {
teamBlue: {
name: this.state.filter
},
teamRed: {
name: this.state.filter
}
};
let filteredMatches = this.state.matches.filter(function(item) {
for (let key in criteria) {
if (item[key] === undefined || item[key] !== criteria[key])
return false;
}
return true;
});
console.log(filteredMatches);
but none of them worked.
Is there any way to filter these matches so when I type "blue" into my input, it will show all matches where team name contains "blue"?
Thanks in advance!
Try updating the condition to:
if (!item[key] || item[key].name !== criteria[key].name)
let filteredMatches = this.state.matches.filter(function(item) {
let flag = true;
for (let key in criteria) {
// update this to
if (!item[key] || item[key].name !== criteria[key].name)
flag = false;
}
return flag;
});
The name property is missing :
if (key in item && item[key].name !== criteria[key].name)
You're comparing objects with === which will return false. You either need to use a deep comparison method from a library, or implement it yourself like below:
const matches = [ {"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": []
},
"teamRed": {
"id": 37,
"name": "nameForTeamRed",
"playerList": []
},
}, {"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": []
},
"teamRed": {
"id": 37,
"name": "nameForTeamRead",
"playerList": []
},
}]
const criteria = {
teamBlue: {
name: 'nameForTeamBlue',
},
teamRed: {
name: 'nameForTeamRed',
}
}
const filteredMatches = matches.filter((item) => {
const allCriteriaMatched = Object.entries(criteria)
.every(([key, value]) => {
const matched = Object.entries(value).every(([criteriaKey, criteriaValue]) => {
const itemValue = item[key][criteriaKey]
const matched = itemValue == criteriaValue
if (!matched) console.log('Item %s does not matched criteria %s. Item\'s value is %s, but criteria value is %s', item[key]['id'], criteriaKey, itemValue, criteriaValue, criteriaValue)
return matched
})
if (!matched) return false
return true
}, {})
return allCriteriaMatched
})
console.log(filteredMatches);
Basically, you just need to go 1 level deeper :D if your criteria can have multiple nested objects, then there's no point doing it manually. You can try to map criteria to run against matches so that you don't use === on objects, but only primitives.

Categories

Resources