This question already has answers here:
Generate a string of names from the 2d array matrix
(2 answers)
Closed 19 days ago.
I have a 2 dimensional array where I need to generate the report.
Expected result
Name#1: 24,26 Jan ----> Name#2
Name#5: 23 - 27 Jan ----> Name#4
Name#6: 23, 25-27 Jan ----> Name#3
The input data
The names of employees working is maintained in the schedule, and the replacements for the day is mentioned.
I have tried using JS, But I am struggling to understand the way it works.
function display() {
const values = [["Name/Date","2023-01-22T18:30:00.000Z","2023-01-23T18:30:00.000Z","2023-01-24T18:30:00.000Z","2023-01-25T18:30:00.000Z","2023-01-26T18:30:00.000Z"],["Name#1","","Name#2","","Name#2",""],["Name#2","","","","",""],["Name#3","","","","",""],["Name#4","","","","",""],["Name#5","Name#4","Name#4","Name#4","Name#4","Name#4"],["Name#6","Name#3","","Name#3","Name#3","Name#3"]]
for (var i = 1; i < values.length; i++) {
if (values[i][0]) {
var string = [];
for (var j = 1; j < values[i].length; j++) {
if (values[i][j]) {
string.push(values[i][j])
}
}
}
console.log(schedule)
}
}
Sure. Given your data, you can do this in two loops,
gathering all of the replacement dates
looping over those per-person replacement dates to find the runs of a single replacement
The final formatting of the date strings to your desired format is left as a separate exercise.
const values = [
['Name/Date', '2023-01-22T18:30:00.000Z', '2023-01-23T18:30:00.000Z', '2023-01-24T18:30:00.000Z', '2023-01-25T18:30:00.000Z', '2023-01-26T18:30:00.000Z'],
['Name#1', '', 'Name#2', '', 'Name#2', ''],
['Name#2', '', '', '', '', ''],
['Name#3', '', '', '', '', ''],
['Name#4', '', '', '', '', ''],
['Name#5', 'Name#4', 'Name#4', 'Name#4', 'Name#4', 'Name#4'],
['Name#6', 'Name#3', '', 'Name#3', 'Name#3', 'Name#3'],
];
// Loop over the data to generate a simple mapping of replacements
const replacementsByPersonAndDate = {};
for (let y = 1; y < values.length; y++) {
let row = values[y];
const person = row[0];
for (let x = 1; x < row.length; x++) {
const date = values[0][x].split('T')[0]; // Just the date
const replacement = row[x];
replacementsByPersonAndDate[person] = replacementsByPersonAndDate[person] || {};
replacementsByPersonAndDate[person][date] = replacement;
}
}
// Loop over the simple mapping to find runs of replacements, and format
for (let [person, replacements] of Object.entries(replacementsByPersonAndDate)) {
let currentRun = null;
let runs = [];
for (let date of Object.keys(replacements).sort()) {
const replacement = replacements[date];
if (!currentRun || replacement !== currentRun.replacement) {
currentRun = null;
if (replacement) { // Only start a new run if there is a replacement
currentRun = {dates: [], replacement};
runs.push(currentRun);
}
}
if(currentRun) {
currentRun.dates.push(date);
}
}
for (const {replacement, dates} of runs) {
if (dates.length > 1) {
console.log(`${person} replaced by ${replacement} on ${dates[0]} through ${dates[dates.length - 1]}`);
} else {
console.log(`${person} replaced by ${replacement} on ${dates[0]}`);
}
}
}
I'd reduce() the values to an object where you group the data as desired. Then you can output it the way you like.
Date format is done with new Date(), this could be improved to group the dates to show eg
24 - 27 instead off 24, 25, 26, 27
Example, which outputs only those with a date found, result is:
Name#1: 2023-01-23, 2023-01-25 --> Name#2
Name#5: 2023-01-22, 2023-01-23, 2023-01-24, 2023-01-25, 2023-01-26 --> Name#4
Name#6: 2023-01-22, 2023-01-24, 2023-01-25, 2023-01-26 --> Name#3
function display() {
const values = [
["Name/Date", "2023-01-22T18:30:00.000Z", "2023-01-23T18:30:00.000Z", "2023-01-24T18:30:00.000Z", "2023-01-25T18:30:00.000Z", "2023-01-26T18:30:00.000Z"],
["Name#1", "", "Name#2", "", "Name#2", ""],
["Name#2", "", "", "", "", ""],
["Name#3", "", "", "", "", ""],
["Name#4", "", "", "", "", ""],
["Name#5", "Name#4", "Name#4", "Name#4", "Name#4", "Name#4"],
["Name#6", "Name#3", "", "Name#3", "Name#3", "Name#3"]
]
const headers = values.shift();
const res = values.reduce((p, c, i) => {
const key = c.shift();
const replacementNames = c.filter(Boolean).filter((v, i, a) => a.indexOf(v) === i)[0] ?? 'unkown';
const replacementDates = c.reduce((p, c, i) => {
if (!c) { return p; }
let parsed = new Date(headers[i + 1]).toISOString().split('T')[0]
return [ ...p, parsed ];
}, []);
return { ...p, [key]: { replacementDates, replacementNames } };
}, {});
for (let o in res) {
if (res[o].replacementDates.length) {
console.log(`${o}: ${res[o].replacementDates.join(', ')} --> ${res[o].replacementNames}`);
}
}
}
display();
Related
I have a JSON array having hundreds of objects where each JSON object having name and hobbies property.
Below is the JSON structure:
const data = [
{
name:'Paul',
hobbies: ['Football','Reading']
},
{
name:'Riya',
hobbies: ['Singing','Dancing']
},
{
name:'Jack',
hobbies: ['Gaming']
}
]
So here if I will iterate through this data it will give me same name multiple times wherever multiple hobbies are present.So if I am console it result would be
Paul,Football
Paul,Reading
Riya,Singing
Riya,Dancing
Jack,Gaming
I don't want above output I want wherever there is same name is coming in a same object don't console it like below:
Paul,Football
"",Reading
Riya,Singing
"",Dancing
Jack,Gaming
Below is my code:
const data = [
{
name:'Paul',
hobbies: ['Football','Reading']
},
{
name:'Riya',
hobbies: ['Singing','Dancing']
},
{
name:'Jack',
hobbies: ['Gaming']
}
]
const example = (data) => {
for(var i=0;i<data.length;i++){
for(var j=0;j<data[i].hobbies.length;j++){
console.log(data[i].name,data[i].hobbies[j]);
if(i=0){
console.log(data[i].name,data[i].reports[j]);
}
else{
const prev = i-1;
if(data[prev].name == data[i].name) { //Getting TypeError here cannot read property 'name' of undefined
console.log("",data[i].reports[j]);
}
else{
console.log(data[i].name,data[i].reports[j]);
}
}
}
}
}
example(data);
In above code I am trying to compare the previous value of name in data array with the current value of name. If it's same then making name field " " else putting name value and for first element for position 0 I am putting value as it is.
Why am I getting this TypeError?
There are several issues, first is typo, you assigned instead of comparing
if (i=0) {
// ^^^^^
console.log(data[i].name,data[i].reports[j]);
}
The rest is logic, all you have to do is to check the index of j
const example = data => {
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].hobbies.length; j++) {
if (j == 0) {
console.log(data[i].name, data[i].hobbies[j])
} else {
console.log("", data[i].hobbies[j])
}
}
}
}
Full solution
const data = [
{
name: "Paul",
hobbies: ["Football", "Reading"],
},
{
name: "Riya",
hobbies: ["Singing", "Dancing"],
},
{
name: "Jack",
hobbies: ["Gaming"],
},
]
const example = data => {
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].hobbies.length; j++) {
if (j == 0) {
console.log(data[i].name, data[i].hobbies[j])
} else {
console.log("", data[i].hobbies[j])
}
}
}
}
example(data)
const data = [
{
name:'Paul',
hobbies: ['Football','Reading']
},
{
name:'Riya',
hobbies: ['Singing','Dancing']
},
{
name:'Jack',
hobbies: ['Gaming']
}
]
data.forEach(d => {
d.hobbies.forEach((hobby, index) => {
const name = index == 0 ? d.name : '""'
console.log(name + ',' + hobby)
})
})
Just print the name if index of hobby is 0
I'm working on school-app. person enter students marks from frontend and I've to store it in my backend. I know my data-structure is quite bad. but this is only way I can comfortly use and fit it in my front end application/website.
codeSandbox link
Full Code:
//This data is already set need to push information in this array.
let student = [{
"detail": {
"name": "Mark",
"surname":"widen"
},
}];
//formatting the query in json.
const keys = Object.keys(query)[0].split(",")
const values = Object.values(query)[0].split(",")
const newObj = {}
for (let i = 0; i < keys.length; i++) {
newObj[keys[i]] = values[i]
}
// I've to push it along with "academic-year". so,
for (let a = 0; a < newObj.length; a++) {
const year = a + "st-Year"
console.log(year) // Expected Output: 1st-Year and 2nd-Year
}
// How to run this both for-loop synchronously way ?? AND
//pushing with "ObtainedMarks" and "year" (Error over here)
student.push({
ObtainedMarks: {
year : [
{ physics: newObj }
],
year : [
{ physics: newObj }
]
}
})
console.log(student) //Here's I want expected Output
Expected Output:
let student = [{
"detail": {
"name": "Mark",
"surname":"widen"
},
ObtainedMarks: {
"1st-Year": [
{ physics: { "marks": "500" } } //Physics subject is default.
],
"2nd-Year": [
{ physics: { "mark": "200" } } //Physics subject is default.
]
}
}];
I want to push returned data in student array. with 1st-Year
and 2nd-Year's for-loop.
You can do the conversion in your for-loop
let student = [{
"detail": {
"name": "Mark",
"surname": "widen"
},
}];
let query = {
"marks,mark": "500,200"
}
const keys = Object.keys(query)[0].split(",");
const values = Object.values(query)[0].split(",");
const marks = {}
for (let i = 0; i < keys.length; i++) {
marks[i === 0 ? `${i+1}st-year` : `${i+1}nd-year`] = [{
physics: {
[keys[i]]: values[i]
}
}];
}
student.push({
obtainedMarks: marks
});
console.log(student);
Alternative way: map through the keys and create an object from entries after manipulating the data.
let student = [{
"detail": {
"name": "Mark",
"surname": "widen"
},
}];
let query = {
"marks,mark": "500,200"
}
const keys = Object.keys(query)[0].split(",");
const values = Object.values(query)[0].split(",");
const marks = Object.fromEntries(keys.map((k, i) => {
return [
i === 0 ? `${i+1}st-year`: `${i+1}nd-year`,
[{ physics: { [k]: values[i] }}]
];
}));
student.push({
obtainedMarks: marks
});
console.log(student);
Suppose I have the following array of objects:
myArray = [ { id: 'first', date: '2020-11-30', percentage: 10 }, { id: 'second', date: '2020-10-30', percentage: 20 }, { id: 'first', date: '2020-09-30', percentage: 30 } ]
Basically my question is how to find all the id's that have the same values, then compare their dates to see which has a higher value(I am planning on converting the string with Date.parse) and finally check which has the greater percentage, and then assign a variable to the condition.
Not really sure how to go about it, but figures it looks something like the code below or not, thanks for the help in advance.
for (i = 0; i < myArray.length; i++) {
if (myArray.id[i] === myArray.id[i]) {
if (myArray.date[i] > myArray.date[i]) {
if (myArray.percentage[i] > myArray.percentage[i]) {
let stuff = stuff;
}
}
}
}
You need to remember objects with the id that you've seen earlier so you can compare them with the object you're looking at "now" in each loop iteration. A Map is a good way to do that in modern JavaScript, or an object created with Object.create(null) in ES5.
const lastSeen = new Map();
for (const entry of myArray) {
const {id, date, percentage} = entry;
const last = lastSeen.get(id);
if (last) {
if (date > last.date && percentage > last.percentage) {
// ...this entry is newer than the previous one with the matching ID
// Replace the previous one (and possibly do something with `stuff`?)
lastSeen.set(id, entry);
}
} else {
lastSeen.set(id, entry);
}
}
Live Example:
const myArray = [ { id: 'first', date: '2020-11-30', percentage: 10 }, { id: 'second', date: '2020-10-30', percentage: 20 }, { id: 'first', date: '2020-09-30', percentage: 30 } ];
const lastSeen = new Map()
for (const entry of myArray) {
const {id, date, percentage} = entry;
const last = lastSeen.get(id);
if (last) {
console.log(`Checking ${id} / ${date} / ${percentage}...`);
if (date > last.date && percentage > last.percentage) {
// ...this entry is newer than the previous one with the matching ID
// Replace the previous one (and possibly do something with `stuff`?)
console.log(`Replacing ${id}...`);
lastSeen.set(id, entry);
} else {
console.log(`Not replacing ${id}`);
}
} else {
console.log(`${id} is new, adding...`);
lastSeen.set(id, entry);
}
}
I haven't included setting stuff above because it's not clear what let stuff = stuff; in your original code was meant to do. You can find the latest ones per id in lastSeen or do something where indicated above to handle stuff.
In ES5-level code (but here in 2020 about to be 2021, I strongly recommend writing modern code and using a transpiler if you need to support obsolete environments):
var lastSeen = Object.create(null);
for (let i = 0; i < myArray.length; ++i) {
var entry = myArray[i];
var last = lastSeen[entry.id];
if (last) {
if (entry.date > last.date && entry.percentage > last.percentage) {
// ...this entry is newer than the previous one with the matching ID
// Replace the previous one (and possibly do something with `stuff`?)
lastSeen[entry.id] = entry;
}
} else {
lastSeen[entry.id] = entry;
}
}
Live Example:
const myArray = [ { id: 'first', date: '2020-11-30', percentage: 10 }, { id: 'second', date: '2020-10-30', percentage: 20 }, { id: 'first', date: '2020-09-30', percentage: 30 } ];
var lastSeen = Object.create(null);
for (let i = 0; i < myArray.length; ++i) {
var entry = myArray[i];
var last = lastSeen[entry.id];
if (last) {
console.log(`Checking ${entry.id} / ${entry.date} / ${entry.percentage}...`);
if (entry.date > last.date && entry.percentage > last.percentage) {
// ...this entry is newer than the previous one with the matching ID
// Replace the previous one (and possibly do something with `stuff`?)
console.log(`Replacing ${entry.id}...`);
lastSeen[entry.id] = entry;
} else {
console.log(`Not replacing ${entry.id}`);
}
} else {
console.log(`${entry.id} is new, adding...`);
lastSeen[entry.id] = entry;
}
}
You could reduce the array with an object and check if the key exist or if the wanted properties are greater.
const
data = [{ id: 'first', date: '2020-11-30', percentage: 10 }, { id: 'second', date: '2020-10-30', percentage: 20 }, { id: 'first', date: '2020-09-30', percentage: 30 }],
result = Object.values(data.reduce((r, o) => {
if (
!r[o.id] ||
r[o.id].date < o.date ||
r[o.id].date === o.date && r[o.id].percentage < o.percentage
) {
r[o.id] = o;
}
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am pretty new to angular and was wondering how I can access a LOCAL variable dynamically. Here is the scenario I am facing :
I am declaring 7 objects within an IF statement :
if (...) {
const day1 = { date: null, total: 0 };
const day2 = { date: null, total: 0 };
const day3 = { date: null, total: 0 };
const day4 = { date: null, total: 0 };
const day5 = { date: null, total: 0 };
const day6 = { date: null, total: 0 };
const day7 = { date: null, total: 0 };
}
Later within that IF statement, I need to assign a value to the "total" key depending on calculations also done within that IF statement.
Now, instead of doing something like this later within the IF statement :
day1.date = ... ;
day2.date = ... ;
day3.date = ... ;
day4.date = ... ;
day5.date = ... ;
day6.date = ... ;
day7.date = ... ;
I would like to do something like this to keep my code neat and efficient (obviously, this does not work) :
for (let i = 1; i <= 7; i++) {
['day' + i].date = ... ;
}
It would have worked if the 7 objects were declared globally and then using this['day' + i].date. But the objects being declared locally in the IF statement, I can't use this syntax.
My questions are the following :
Is there something similar for locally declared variables?
Even better, can I declare these 7 local objects dynamically in a for loop?
Thank you for your support.
Best solution: Use an array instead:
Change this:
if (...) {
const day1 = { date: null, total: 0 };
const day2 = { date: null, total: 0 };
const day3 = { date: null, total: 0 };
const day4 = { date: null, total: 0 };
const day5 = { date: null, total: 0 };
const day6 = { date: null, total: 0 };
const day7 = { date: null, total: 0 };
// ...
day1.date = ... ;
day2.date = ... ;
day3.date = ... ;
day4.date = ... ;
day5.date = ... ;
day6.date = ... ;
day7.date = ... ;
}
...to this:
// Declared in module scope:
type Day = { date: Date | null, total: number };
// Inside your function:
if( ... ) {
const days: Day[] = [
{ date: null, total: 0 },
{ date: null, total: 0 },
{ date: null, total: 0 },
{ date: null, total: 0 },
{ date: null, total: 0 },
{ date: null, total: 0 },
{ date: null, total: 0 }
];
//
for( let i = 0; i < 7; i++ ) {
days[i].date = ...
}
}
You can also initialize days in a loop too:
const days: Day[] = [];
for( let i = 0; i < 7; i++ )
{
days[i] = { date: null, total: 0 };
}
And you can have named references to elements in the array if you want to keep on using day1, day2, etc (but remember these are references to the object values in the array rather than being aliases to array indexes):
const day1 = days[0];
const day2 = days[1];
...though try not to let your 1-based day numbering be confused with JavaScript/TypeScript's 0-based array indexing.
Worst solution: Using eval:
You can manipulate locals using eval(), but you shouldn't use eval(), ever. But you can do this:
if (...) {
const day1 = { date: null, total: 0 };
const day2 = { date: null, total: 0 };
const day3 = { date: null, total: 0 };
const day4 = { date: null, total: 0 };
const day5 = { date: null, total: 0 };
const day6 = { date: null, total: 0 };
const day7 = { date: null, total: 0 };
for (let i = 1; i <= 7; i++) {
const expr = 'day' + i + ' = ...;';
console.log( expr );
eval( expr );
}
}
I have an Array full of transactions and I want to divide it by day. It will be an array of date that is and array of transations. It may be a little messy but I want to return this structure.
What I tried to do returns me the structure I want, but I don't know how to merge duplicated key values.
This is the array
const transactions = [
{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
This is what I already tried by now
const days = [];
const finalArray = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const datesToMatch = [...new Set(days)].map((date) => {
return { [date]: null };
});
transactions.map((transaction) => {
datesToMatch.map((dayObject) => {
const day = Object.keys(dayObject).toString();
if (day === transaction.day) {
finalArray.push({ [day]: [transaction] });
}
});
});
The output
[ { '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Expected output
[ { '2020-05-12T00:00:00.000Z': [ [Object, Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Thanks!
Explanation:
dates : extract dates from both fields
uniqueDates : build a Set and convert it into an array so it only has uniqueDates
dateToTransactions : map every unique date to an object with one key (itself) and filter every transaction that is equal to it.
const transactions = [{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
const dates = transactions.map(x => {
const received = x.receiveDate || [];
const paid = x.paidDate || [];
return received + paid;
});
const uniqueDates = [...new Set(dates)];
const dateToTransactions =
uniqueDates.map(
date => {
sameDate = transactions.filter(x => x.receiveDate === date || x.paidDate == date);
return {[date]: sameDate};
});
console.log(dateToTransactions);
I would do something like this:
const days = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const result = new Map();
days.forEach((day) => {
result.set(day, [])
});
transactions.forEach((transaction) => {
let r = result.get(transaction.day);
r.push(transaction);
result.set(transaction.day, r);
});
Then, in the result map you have a list of the transactions that were made for each day.
This will give the result you expect
const days = {};
const finalArray = transactions.forEach((transaction) => {
let date = (transaction.receiveDate || transaction.paidDate)
if (!days[date]) { days[date] = [transaction]}
else {days[date].push(transaction)}
});
console.log(days);