How to map an array in order to change it? - arrays

I need to map an array of objects
array=[{a:'',b:firstname,c:'',d:lastname},{a:'',b:firstname,c:'',d:lastname}]
while mapping if an element of object of the array does contain : '', i will return to to null so the result will be like that :
array=[{a:null,b:firstname,c:null,d:lastname},{a:null,b:firstname,c:null,d:lastname}].

It should do what you expect in your particular case (only with a, b, c keys):
const newArray = array.map(({a,b,c}) => {
return {a: !!a ? a: null, b: !!b : null, !!c : c : null }
})

You could create helper function so you can easily change your condition and mapping.
function transform(array, mapFn) {
return array.map((obj) => {
const newObj = {};
Object.keys(obj).map(function(key) {
newObj[key] = mapFn(obj, key);
});
return newObj;
});
}
const array = [{a:'',b:"f1",c:'',d:"f2"},{a:'',b:"f3",c:'',d:"f4"}];
const newArray = transform(array, (obj, key) => {
const value = obj[key];
return value === '' ? null : value;
})
With this you have full control over mapping function, and later if you have to for example handle not only empty string but also undefined values and map them to null, you can do it easily by providing changed mapFn.

Related

How correctly copy and modify an array in typescript?

I'm trying to copy an array, replace some elements in it and then replace the original array with the copy containing the new elements.
Here's my code:
type Span = {
start: number
end: number
}
const handleSplitClick = (span: Span, tag: string) => {
let copy = props.value.map(a => {return{...a}})
const splitIndex = copy.findIndex(s => s.start === span.start && s.end === span.end)
if (splitIndex != -1 ){
const tagIndex = (copy[splitIndex] as any).tags.findIndex((t:string) => t == tag)
if (tagIndex > -1){
(copy[splitIndex] as any).tags.splice(tagIndex, 1)
console.log(copy)
console.log(props.value)
}
}
}
Here's how props.value looks:
I'm trying to modify the tags array within props.value.
I tried to initialise the copy of the array in these ways:
//1
let copy = props.value.map(a => {return{...a}})
//2
let copy = [...props.value]
//3
let copy = props.value.map(a => Object.assign({}, a));
Regardless of what I do, when I try to remove the particular element from tags:
(copy[splitIndex] as any).tags.splice(tagIndex, 1)
Both the original props.value and copy get modified.
How can I correctly achieve this?
Thanks.
It looks like you want to create a new array where you've removed the matching tag from the tags array when its start and end match, and that you want to do this immutably (that is, without changing the original array or original element object, like a state update in React and similar). To do that, in map return the other elements unchanged, and return a new element with the updated tags for the one that matches:
const handleSplitClick = (span: Span, tag: string) => {
// Use `map` to create the new array
const copy = props.value.map((element) => {
// Is this the element we want to update?
if (element.start === span.start && element.end === span.end) {
// Yes, return an updated copy with the first tag removed
return {
...element,
tags: element.tags.filter((t) => t !== tag),
};
}
// No, just return the element unchanged
return element;
});
// ...use or return `copy`...
};
Or if you prefer keeping things really terse:
const handleSplitClick2 = (span: Span, tag: string) => {
// Use `map` to create the new array
const copy = props.value.map((element) =>
element.start === span.start && element.end === span.end
? {
...element,
tags: element.tags.filter((t) => t !== tag),
}
: element
);
// ...use or return `copy`...
};
Note that in the vast majority of cases, you don't need or want type annotations on the callback parameters for map or filter; TypeScript will infer them correctly:
Live version with TypeScript commented out:
const props = {
value: [
{start: 0, end: 1, tags: ["a", "b", "c"]},
{start: 1, end: 2, tags: ["a", "b", "c"]},
// ^^^ The one we'll target
{start: 2, end: 3, tags: ["b", "c"]},
]
}
const handleSplitClick = (span/*: Span*/, tag/*: string*/) => {
// Use `map` to create the new array
const copy = props.value.map((element) => {
// Is this the element we want to update?
if (element.start === span.start && element.end === span.end) {
// Yes, return an updated copy with the first tag removed
return {
...element,
tags: element.tags.filter((t) => t !== tag),
};
}
// No, just return the element unchanged
return element;
});
console.log(JSON.stringify(copy, null, 4));
};
handleSplitClick({start: 1, end: 2}, "b");
.as-console-wrapper {
max-height: 100% !important;
}

using array for URLSearchParams in vue3

i want to append key and value of array , using for axos request
here is the array
const
schedule = ref({
"userId" : 13,
"sunday" : ["mornig","afternoon","nigh"],
"monday" : ["afternoon","nigh"],
"wednesday" : ["mornig","afternoon"]
})
to append manuallya i can do like this
params.append("userId",data.value.userId)
params.append("sunday[0]",data.value.sunday[0])
params.append("sunday[1]",data.value.sunday[1])
params.append("sunday[2]",data.value.sunday[2])
params.append("monday[0]",data.value.monday[0])
params.append("monday[1]",data.value.monday[1])
params.append("wednesday[0]",data.value.wednesday[0])
params.append("wednesday[1]",data.value.wednesday[1])
but this will be problim if length of the schedule time l (morning,night ...) unknown
i do like this
let i = 0
for(let j in data.value){
console.log(j+$[i++])
}
and also loop using for in and for of , but none of them are success
You "just" need to do a nested iteration. Loop through object, and if any value is an array, loop through the array. Here's an example code to flatten the dataset. Just note that instead of flattenData(schedule) you'd need to pass the ref's value with flattenData(schedule.value).
const schedule = {
userId: 13,
sunday: ["mornig", "afternoon", "nigh"],
monday: ["afternoon", "nigh"],
wednesday: ["morning", "afternoon"],
};
function flattenData(data) {
const o = {};
Object.keys(data).forEach((dataKey) => {
if (Array.isArray(data[dataKey])) {
data[dataKey].forEach(
(_, nestedArrayIndex) =>
(o[`${dataKey}[${nestedArrayIndex}]`] =
data[dataKey][nestedArrayIndex])
);
} else {
o[dataKey] = data[dataKey];
}
});
return o;
}
// show flattened data
console.log(flattenData(schedule));
// prepare params
const params = new URLSearchParams("");
// populate
Object.entries(flattenData(schedule)).forEach(([k,v]) => params.append(k, v))
// result:
console.log(params.toString())

How to filter object and return only key value if key is uppercase

var params = {
"rn": "AuditTrailLogon",
"Dateange": "lastquarter",
"App": "20000",
"ts": "AuditTrailLogon"
}
let filtered = Object.keys(params)
.filter(key => key.toUpperCase() === key);
console.log("filtered", filtered);
How can I filter the object and return only the ones that are uppercase keys
var params = {
"rn": "AuditTrailLogon",
"Dateange": "lastquarter",
"App": "20000",
"ts": "AuditTrailLogon"
}
Tried .filter method but it return null
let filtered = Object.keys(params )
.filter(key => key.toUpperCase() === key);
console.log("filtered", filtered); returns null []
how to get
{
"Dateange": "lastquarter",
"App": "20000",
}
Convert the object to entries (Object.entries()), filter the entries(I've used a regex), and then convert back to object with Object.fromEntries():
const params = {
"rn": "AuditTrailLogon",
"Dateange": "lastquarter",
"App": "20000",
"ts": "AuditTrailLogon"
}
const uppercaseTest = /^[A-Z]/
const result = Object.fromEntries(
Object.entries(params)
.filter(([key]) => uppercaseTest.test(key))
)
console.log(result)
You are converting the key to Uppercase, so when you compare the keys you get something like this:APP === App, but if you want to compare the keys just by the first character of the key capitalized, you can do something like this:
let filtered = Object.keys(params )
.filter(key => {
let capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
return capitalizedKey === key
});

How can I map an object in order to change it?

I need to map an object
obj={a:'',b:firstname,c:'',d:lastname}
while mapping if an element of an object does contain : '', i will return to to null so the result will be like that :
obj={a:null,b:firstname,c:null,d:lastname}.
How can I do that?
You can use Object.keys to get an array of all the property names in the object, and then use reduce to build up a new object where all properties with value '' get the value null instead.
const obj = { a: "", b: "foo", c: "", d: "bar" };
const result = Object.keys(obj).reduce((acc, key) => {
acc[key] = obj[key] === '' ? null : obj[key];
return acc;
}, {});
console.log(result);
You can do this by using for in
var obj = {a:'',b:'firstname',c:'',d:'lastname'}
for(var key in obj){
if(obj[key] === ""){
obj[key] = null
}
}
console.log(obj)

What is the Best way to loop over an array in scala

I'm new to scala and I'm trying to refactor the below code.I want to eliminate "index" used in the below code and loop over the array to fetch data.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer: ListBuffer[Context] = ListBuffer()
var index = 0
contextListBufferForSubGroup.foreach { contextIndividual =>
MetricContextListBuffer += Context(
entity = contextIndividual,
value = instanceIndividual(index).toString
)
index += 1
}
}
For instance, if the values of variables are as below:
contextListBufferForSubGroup = ("context1","context2")
subgroupMetricIndividual.instances = {{"Inst1","Inst2",1},{"Inst3","Inst4",2}}
Then Context should be something like:
{
entity: "context1",
value: "Inst1"
},
{
entity: "context2",
value: "Inst2"
},
{
entity: "context1",
value: "Inst3"
},
{
entity: "context2",
value: "Inst4"
}
Note:
instanceIndividual can have more elements than those in contextListBufferForSubGroup. We must ignore the last extra elements in instanceIndividual in this case
You can zip two lists into a list of tuples and then map over that.
e.g.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup.zip(instanceIndividual).map {
case (contextIndividual, instanceIndividualIndex) => Context(
entity = contextIndividual,
value = instanceIndividualIndex.toString
)
}
}
If Context can be called like a function i.e. Context(contextIndividual, instanceIndividualIndex.toString) then you can write this even shorter.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup
.zip(instanceIndividual.map(_.toString)).map(Context.tupled)
}
Without knowing your exact datatypes, I'm mocked up something which is probably close to what you want, and is slightly more functional using maps, and immutable collections
case class Context(entity:String, value:String)
val contextListBufferForSubGroup = List("context1","context2")
val subgroupMetricIndividualInstances = List(List("Inst1","Inst2",1),List("Inst3","Inst4",2))
val result: List[Context] = subgroupMetricIndividualInstances.map { instanceIndividual =>
contextListBufferForSubGroup.zip(instanceIndividual) map { case v: (String, String) =>
Context(
entity = v._1,
value = v._2
)
}
}.flatten

Resources