Convert array to object using values like keys - arrays

I have a project in Typescript in which I am trying to create a function that converts an array into an object using the first values as keys of the object.
This is my array:
let testArr = ["id", "ser", "add", "1", "asd", "82.255", "2", "ert", "82.119", "3", "pol", "82.250"];
This is what I need:
let newArr = [
{
"id": "1",
"ser": "asd",
"add": "82.255"
},
{
"id": "2",
"ser": "ert",
"add": "82.119"
},
{
"id": "3",
"ser": "pol",
"add": "82.250"
}
]
In result I store the data of the array that I want to use as keys of the object:
let chunk = 3;
let result = testArr.reduce((resultArray, item, index) => {
const chunkIndex = Math.floor(index/chunk)
if(!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [] // start a new chunk
}
resultArray[chunkIndex].push(item)
return resultArray
}, [])
My problem is that I don't know how to use that data as keys of the object and I would like to know how to convert the result variable into a generic function for any array and any number.

You can iterate over the testArr array using forEach and check the index. if it's a multiple of 3 you can assign an object with the values and push that object to the new array.
For your case, i've modified the answer to a generic case where you can pass the starting index of the values in the original array
let testArr = ["id", "ser", "add", "1", "asd", "82.255", "2", "ert", "82.119", "3", "pol", "82.250"];
const arr = [];
function genericArrayFormatter(checkIdx){
testArr.forEach((val, idx) => {
if (idx > checkIdx - 1 && idx % checkIdx === 0){
const obj = {};
let i = 0;
let index = idx;
while (checkIdx > i){
obj[testArr[i++]] = testArr[index++];
}
arr.push(obj);
}
});
}
genericArrayFormatter(3);
console.log(arr);

Related

Difficulty finding type of nested indexes

I am having trouble assigning a type to this numsToLtrsMap[usr_query[idx]]. The numsToLtrsMap is an object of keys that are strings and the values that are strings. I am new to Typescript and have found no solution for it
Playground Link: Provided
const convertToLtrCombos = (usr_query: string) => {
const result: string[] = [];
const numsToLtrsMap ={
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz",
};
//recursive fn
const scan = (currStr: string, idx: number) => {
//if idx is in last digit
if (idx > usr_query.length - 1) {
//we push string to result array
result.push(currStr);
return;
}
{
/*each letter a usr press gives ref to the key of the value of usr_query based on the idx value of usr_query*/
}
const letters = numsToLtrsMap[usr_query[idx]];
for (const ltr of letters) {
//concatenate new ltr to string, then move to next idx
scan(currStr + ltr, idx + 1);
}
};
// call fn starting with an empty string at first idx
scan("", 0);
return result;
};
I have tried to assign usr_query as a string and change the numsToLtrsMap as an array of objects. That clear one error but inside the nested indexes gives me an error.

NODEJS : Want To Create an Array of objects, with only one key's value set to empty in each Object

I have
obj1 = {
"place": "{{base_gplaceId}}",
"subPlace": "{{base_gsubPlaceId}}",
"user": "{{base_userId}}",
};
I want
var newArr = [{
"place": "",
"subPlace": "{{base_gsubPlaceId}}",
"user": "{{base_userId}}",
}, {
"place": "{{base_gplaceId}}",
"subPlace": "",
"user": "{{base_userId}}"
}, {
"place": "{{base_gplaceId}}",
"subPlace": "{{base_gsubPlaceId}}",
"user": ""
}];
Following is my Code
var newArr = [];
const obj1 = {
"place": "{{base_gplaceId}}",
"subPlace": "{{base_gsubPlaceId}}",
"user": "{{base_userId}}",
};
KEYS = Object.keys(obj1);
KEYS.forEach(function (element) {
var object2 = null;
console.log("init:", object2);
object2 = obj1;
console.log("object2:", object2);
console.log("element:", element);
console.log("object2 element VAL:", object2[element]);
object2[element] = "";
console.log("OBJ VAL:", object2, "\n---------------");
newArr.push(object2);
});
console.log(newArr);
Some how mid way obj1 is being set to empty values, and hence object2 is being set with empty values not getting Expected Values.
Objects are assigned by reference. When you set object2 = obj1; and then change object2, obj1 will change as well. Doing that in a loop causes the side effects you're seeing.
Copy the object using object2 = Object.assign({}, obj1); instead.

Empty array when looping json array in Nodejs

I want to get specific data from JSON array in adonisjs. But I have some problem to get that data. When I'm looping this JSON array the return just only empty array = []. This is my controller code:
const detail= await TrxHistory.query()
.where('id_trx', params.id_trx)
.fetch()
This return json array:
[
{
"id_trx_history": "1",
"id_trx": "3",
"trx_status": "shop_confirm",
"created_at": "2019-10-18 22:27:54"
},
{
"id_trx_history": "1",
"id_trx": "3",
"trx_status": "shop_process",
"created_at": "2019-10-18 22:29:48"
},
]
And i'm try to get data from row "trx_status", using looping like this:
let data = [];
for(var i = 0; i < detail.length; i++) {
data[i] = detail[i]["trx_status"];
}
console.log(data);
What's wrong with this code?
When you fetch adonis lucid request you need to use .rows. Like:
... // Your query
let fooData = [];
detail.rows.forEach(de => {
fooData.push(el.trx_status)
})
How to use?
detail.rows[1]
detail.rows.length
If detail has a structure that you've shown, then it should work perfectly:
const detail = [
{
"id_trx_history": "1",
"id_trx": "3",
"trx_status": "shop_confirm",
"created_at": "2019-10-18 22:27:54"
},
{
"id_trx_history": "1",
"id_trx": "3",
"trx_status": "shop_process",
"created_at": "2019-10-18 22:29:48"
},
];
let data = [];
for (let i = 0; i < detail.length; i++) {
data[i] = detail[i]["trx_status"];
}
console.log(data);
// another way:
let fooData = [];
detail.forEach(el => {
el["trx_status"] ? fooData.push(el["trx_status"]) : null;
});
console.log(fooData);

How best to Compare JSON object values to a fixed array in JScript

I would like to compare JSON values to an array of values but I d'ont know what's the best scenario to go with.
I got a JSON object with expected values (could have 1 value , 2 or more)
I have a DB function that returns a fix number of values, say 10 values all the time and I would like to know if my JSON values matches the right one coming from DB.
Ex:
My JSON var is :
var expValues = {
"id": "123",
"age": 23
};
My DB will push some values to an Array of objects.
Ex:
if ((rs.BOF) && (rs.EOF))
{
//nothing found;
}
else
{
while (!rs.EOF)
{
aDetails.push(
{
"id": rs.fields("id").Value,
"name": rs.fields("name").Value,
"age": rs.fields("age").Value,
"sex": rs.fields("sex").Value,
"hobby": rs.fields("hobby").Value
});
rs.MoveNext();
}
}
rs.close;
//Close connection then return
return aDetails;
basically I want to make sure values coming from JSON match the right ones coming from DB. (id for example).
I have assumed aDetails to have something like below data.
let aDetails = [{
"id": "123",
"name": "as",
"age": 23,
"sex": "m",
"hobby": "abc"
}, {
"id": "1234",
"name": "as1",
"age": 23,
"sex": "m",
"hobby": "abc"
}, {
"id": "12",
"name": "as2",
"age": 23,
"sex": "m",
"hobby": "abc"
}]
var expValues = {
"id": "123",
"age": 23
};
function isObjectMatched(obj) {
return aDetails.some(d => Object.entries(obj).every(([k, v]) => d[k] == v))
}
console.log(isObjectMatched(expValues))
This is a general purpose way of indexing list of objects for fast retrieval with any configuration of properties.
// javascript version
function makeIndex (arrayOfObject, listOfPropertyToIndex) {
var index = {};
index.objToKey = function (o) {
var key = [];
listOfPropertyToIndex.forEach((p) => {
key.push(""+o[p]);
});
return key.join("_");
};
arrayOfObject.forEach((o) => {
index[objToKey(o)] = o;
});
index.match = function (object) {
var key = index.objToKey(object);
if (index.hasOwnProperty(key)) {
return index[key];
};
return null;
});
return index;
}
// jscript version
function makeIndex (arrayOfObject, listOfPropertyToIndex) {
var index = {};
index.objToKey = function (o) {
var key = [];
for (var p in o) {
if (o.hasOwnProperty(p)) {
key.push(""+o[p]);
}
}
return key.join("_");
};
for (var i = 0; i < arrayOfObject.length; ++i) {
index[objToKey(arrayOfObject[i])] = o;
}
index.match = function (object) {
var key = index.objToKey(object);
if (index.hasOwnProperty(key)) {
return index[key];
};
return null;
});
return index;
}
Here is how to use it
var expValues = {
"id": "123",
"age": 23
};
var index = makeIndex(aDetails, ["id","age"]);
var obj = index.match(expValues);
if (obj) {
... obj ...
}
var index_name = makeIndex(aDetails, ["name"]);
var person = {"name":"as2"};
var obj2 = index_name.match(person);
if (obj2) {
... obj2 ...
}

How may I functionally transform array of objects into a different structure

I've got an array of fonts which each have a familyName and a fontName.
I would like to transform them into an array of tuples in the form (familyName: String, fontNames: [String]).
I feel like there should be an easy functional way to do this, but can't work it out. The closest I've got is two calls to reduce: First into a dictionary and then into an array.
let dictionary = fonts.reduce(into [String : [String]]() ) { result, font in
let array = result[font.fontFamily] ?? []
result[fontFamily] = array + [font.fontName]
}
let array = dictionary(into: [(String, [String])]() ) { result, element in
result.append( (element.key, element.value.sorted()) )
}.sorted { $0.0 < $1.0 }
I'm also sorting the array of tuples and the array of fontNames in the array of tuples.
Is there a way I can avoid the intermediary dictionary?
Many thanks.
Update
I created a playground to show sanjaykmwt the results of their suggestions:
struct Font {
let family: String
let name: String
}
let fonts = [
Font(family: "ABC", name: "abc"),
Font(family: "ABC", name: "def"),
Font(family: "ABC", name: "ghi"),
Font(family: "XYZ", name: "xyz"),
Font(family: "XYZ", name: "uvw")
]
let sortedFamily = fonts.sorted(by: { (lhs, rhs) -> Bool in
return lhs.family < rhs.family
})
let dict = sortedFamily.map({["family":$0.family,
"fonts":$0.name]})
print("dict: \(dict)")
Output:
dict: [["family": "ABC", "fonts": "abc"], ["family": "ABC", "fonts": "def"], ["family": "ABC", "fonts": "ghi"], ["family": "XYZ", "fonts": "xyz"], ["family": "XYZ", "fonts": "uvw"]]
if You have an array of Fonts with fontFamily, fontName
you can make grouping then map
// Array Of Fonts Example
let array = [Font.init(fontFamily: "Cago", fontName: "AA"),
Font.init(fontFamily: "Cago", fontName: "CCCC"),
Font.init(fontFamily: "Mango", fontName: "AAsss"),
Font.init(fontFamily: "Mango", fontName: "mngoo")]
// Grouping
let groupedByFamilayName = Dictionary.init(grouping: array) {$0.fontFamily}
// Map
let arrayOfTuple = groupedByFamilayName.map { (key,array) -> (String,[String]) in
return (key,array.map({$0.fontName}))
}
print(arrayOfTuple)
Expanding (or contracting!) on Abdelahad Darwish's answer…
let tuples = Dictionary(grouping: fonts) { $0.family }
.map { (familyName: $0.key, fontNames: $0.value.map { $0.name }) }
print(tuples)
[(familyName: "XYZ", fontNames: ["xyz", "uvw"]), (familyName: "ABC", fontNames: ["abc", "def", "ghi"])]
let sortedFamily = fonts.sorted(by: { (lhs, rhs) -> Bool in
return lhs.family < rhs.family
})
let dict = sortedFamily.map({["family":$0.family,"fonts":$0.fonts.sorted()]})
try and print the dict you will get everything sorted
if you want even shorter it can be:
let dict = fonts.sorted(by: { (lhs, rhs) -> Bool in
return lhs.family < rhs.family
}).map({["family":$0.family,"fonts":$0.fonts.sorted()]})

Resources