我需要将日期数组压缩到他们的月份。
我想使用slice方法和库moment.js,将数组压缩到它们的月份。
在这里,我得到了数组当前日期的月份的最后日期。
//Variables
$Host = 'localhost';
$UserName = 'root';
$Password = 'NOP';
$DataBaseName = 'BoosTemplatesDB';
$DEBUG = True;
$link = mysqli_connect($Host, $UserName, $Password, $DataBaseName);
$query_items = 'SELECT * FROM Products WHERE ID = 6';
$result = $link->query($query_items);
if (mysqli_num_rows($result) > 0) {
// Fetch one and one row
while ($row = $result->fetch_assoc()) {
echo $row[1];
}
} else {
echo 'No result found';
}
给出一个带有日期和数据的数组。我需要把它压缩到几个月。
const dateString = moment (lastIndexTemp, "DD.MM.YYYY")
.endOf ("month")
.format ("DD.MM.YYYY");
预期结果:
const dates = [
{ date: "26.06.2019", someData: "foo" },
{ date: "27.06.2019", someData: "foo" },
{ date: "28.06.2019", someData: "foo" },
{ date: "29.06.2019", someData: "foo" },
{ date: "30.06.2019", someData: "foo" },
{ date: "01.07.2019", someData: "foo" },
{ date: "02.07.2019", someData: "foo" },
{ date: "03.07.2019", someData: "foo" },
{ date: "04.07.2019", someData: "foo" },
{ date: "05.07.2019", someData: "foo" },
{ date: "06.07.2019",someData: "foo" },
...
{ date: "08.08.2019",someData: "foo" }
];
感谢您的帮助。
答案 0 :(得分:1)
让我们将此任务分解为单独的部分:
由于输入数据中的字符串表示日期,因此在进行其他操作之前先将其转换。我定义了一个辅助函数,以构造将字符串解析为片刻的新对象:
const DateEntry = ({ date, someData }) => ({
date: moment(date, "DD.MM.YYYY"),
data: someData
});
const dateEntries = dates.map(DateEntry); // Now, we can use momentjs for our date logic
现在我们有了日期列表,我们可以按月对它们进行分组。我实现了一个快速的groupBy
帮助程序,您可以复制它,也可以使用下划线或ramda之类的库中的程序。
要按月分组,我们传递了一个每月返回唯一字符串的函数:
const entriesByMonth = groupBy(
({ date }) => date.format("MM.YYYY"),
entries
);
现在,我们停留在同一日期的条目组。您希望最终得到一个简单的对象列表,并且想要在date
标签中掌握它们的范围。
同样,我们可以定义一个辅助函数,将这些组转换为更易于使用的对象:
const EntryRange = ( dateEntries ) => {
const dates = dateEntries.map(d => d.date);
const data = dateEntries.map(d => d.data);
const from = moment.min(dates);
const to = moment.max(dates);
return { dates, data, from, to };
};
const ranges = Object.values(entriesByMonth).map(EntryRange);
现在,我们有了一个简单的对象列表;每月条目一个对象。这些对象已经知道它们的开始和结束日期!
剩下要做的就是编写一个函数,将EntryRange
对象转换回您想要的格式:
ranges.map(({ from, to, data }) => ({
date: `${from.format("DD.MM.YYYY")} - ${to.format("DD.MM.YYYY")}`,
data: data[0]
}))
请注意,创建字符串可以利用momentjs的格式化方法!
这是可运行代码段中的代码。
// 1: Raw input data
const dates = [
{ date: "26.06.2019", someData: "foo" },
{ date: "27.06.2019", someData: "foo" },
{ date: "28.06.2019", someData: "foo" },
{ date: "29.06.2019", someData: "foo" },
{ date: "30.06.2019", someData: "foo" },
{ date: "01.07.2019", someData: "foo" },
{ date: "02.07.2019", someData: "foo" },
{ date: "03.07.2019", someData: "foo" },
{ date: "04.07.2019", someData: "foo" },
{ date: "05.07.2019", someData: "foo" },
{ date: "06.07.2019", someData: "foo" },
{ date: "08.08.2019", someData: "foo" },
{ date: "01.01.2020", someData: "foo" },
];
// 2: Define models
const DateEntry = ({ date, someData }) => ({
date: moment(date, "DD.MM.YYYY"),
data: someData
});
const EntryRange = ( dateEntries ) => {
const dates = dateEntries.map(d => d.date);
const data = dateEntries.map(d => d.data);
const from = moment.min(dates);
const to = moment.max(dates);
return {
dates,
data,
from,
to
}
};
EntryRange.sorter = (r1, r2) => r1.from.isBefore(r2.from) ? -1 : 1;
// 3. Convert data to easy-to-work-with formats
const entries = dates.map(DateEntry);
const entriesByMonth = groupBy(
({ date }) => date.format("MM.YYYY"),
entries
);
// Sorted list of EntryRanges
const entryGroups = Object
.values(entriesByMonth)
.map(EntryRange)
.sort(EntryRange.sorter);
// 4. Convert back to desired output
console.log(
entryGroups
.map(({ from, to, data }) => ({
date: `${from.format("DD.MM.YYYY")} - ${to.format("DD.MM.YYYY")}`,
data: data[0]
}))
)
// Utils
function groupBy(getKey, items) {
return items.reduce(
(groups, item) => {
const k = getKey(item);
if (!groups[k]) groups[k] = [ item ];
else groups[k].push(item);
return groups;
}, {});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
现在我们有一段代码可以简化每一步,我们可以通过编写一些小的更改来做很多事情。我将作两个更改,只是为了表明我们可以:)
,
联接不同的数据条目亲自尝试一下,看看如何获得不同的结果!
// 1: Raw input data
const dates = [
{ date: "26.06.2019", someData: "foo" },
{ date: "27.06.2019", someData: "foo" },
{ date: "28.06.2019", someData: "foo" },
{ date: "29.06.2019", someData: "foo" },
{ date: "30.06.2019", someData: "bar" },
{ date: "01.07.2019", someData: "foo" },
{ date: "02.07.2019", someData: "foo" },
{ date: "03.07.2019", someData: "foo" },
{ date: "04.07.2019", someData: "foo" },
{ date: "05.07.2019", someData: "foo" },
{ date: "06.07.2019", someData: "foo" },
{ date: "08.08.2019", someData: "foo" },
{ date: "01.01.2020", someData: "foo" },
];
// 2: Define models
const DateEntry = ({ date, someData }) => ({
date: moment(date, "DD.MM.YYYY"),
data: someData
});
const EntryRange = ( dateEntries ) => {
const dates = dateEntries.map(d => d.date);
const data = dateEntries.map(d => d.data);
const from = moment.min(dates);
const to = moment.max(dates);
return {
dates,
data,
from,
to
}
};
EntryRange.sorter = (r1, r2) => r1.from.isBefore(r2.from) ? -1 : 1;
// 3. Convert data to easy-to-work-with formats
const entries = dates.map(DateEntry);
const entriesByYear = groupBy(
({ date }) => date.format("YYYY"),
entries
);
// Sorted list of EntryRanges
const entryGroups = Object
.values(entriesByYear)
.map(EntryRange)
.sort(EntryRange.sorter);
// 4. Convert back to desired output
console.log(
entryGroups
.map(({ from, to, data }) => ({
date: `${from.format("DD.MM.YYYY")} - ${to.format("DD.MM.YYYY")}`,
data: [...new Set(data)].join(", ")
}))
)
// Utils
function groupBy(getKey, items) {
return items.reduce(
(groups, item) => {
const k = getKey(item);
if (!groups[k]) groups[k] = [ item ];
else groups[k].push(item);
return groups;
}, {});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
答案 1 :(得分:0)
您可以通过遍历当前数组并将第一个对象复制到该数组并将date属性更新为当前范围来生成新对象的新数组。然后,对于每个后续日期为同一月第二天的后续对象,将结果数组中最后一个对象的日期值作为最新日期。
否则,将具有更新的日期值的新对象添加到数组。如果日期顺序中断,则会在当月创建多个范围。尚不清楚这是否是您想要的。
例如下面使用几个简单的助手来分析字符串并添加一天。您可以根据需要将其替换为库调用。
不清楚要保留哪个“ someData”,以下保留第一个,但可以轻松保留最后一个。
let dates = [
{ date: "26.06.2019", someData: "foo" },
{ date: "27.06.2019", someData: "foo" },
{ date: "28.06.2019", someData: "foo" },
{ date: "29.06.2019", someData: "foo" },
{ date: "30.06.2019", someData: "foo" },
{ date: "01.07.2019", someData: "foo" },
{ date: "02.07.2019", someData: "foo" },
{ date: "03.07.2019", someData: "foo" },
{ date: "04.07.2019", someData: "foo" },
{ date: "05.07.2019", someData: "foo" },
{ date: "06.07.2019", someData: "foo" },
{ date: "08.08.2019", someData: "foo" }
];
// Parse DD.MM.YYYY to Date. Seperator can be
// any non–digit character
function parseDMY(s) {
let b = s.split(/\D/);
return new Date(b[2], b[1]-1, b[0]);
}
// Return a new date that is the passed date + 1 day
function addDay(date) {
let d = new Date(+date);
d.setDate(d.getDate() + 1);
return d;
}
let result = dates.reduce((acc, obj) => {
// Copy the passed in object
let temp = Object.assign({}, obj);
// Get the last entry in accumulator, use a default object if first iteration
let last = acc.length? acc[acc.length - 1] : {date:' - '};
// Get the current date as string
let currentS = temp.date;
// Get the current date as Date
let currentD = parseDMY(currentS);
// Get the previous end date as Date,
let lastEndD = parseDMY(last.date.split(' ')[2]);
// Get the next day as Date
let lastEndNextD = addDay(lastEndD);
// If current date is the day after last end date
// and in the same month, update date range
if (+currentD == +lastEndNextD &&
currentD.getMonth() == lastEndD.getMonth()) {
last.date = last.date.replace(/\S+$/, currentS)
// Otherwise, start a new entry with an updated range
} else {
temp.date = temp.date + ' - ' + temp.date;
acc.push(temp);
}
return acc;
}, []);
console.log(result);