按月和年排序数组

问题描述 投票:20回答:9

我需要帮助按月和年分类数组以分别显示在图表上。

Array1: ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'....];
Desired Output : [....'Apr18','May18','Jun18','Jul18','Jan19','Mar19'];

根据上面的数组,我还有另一个数组,每个月都有值

Array2: ['Mar19_value','Apr18_value','Jun18_value','Jul18_value','May18_value'
       ,'Jan19_value'....];

Array2: ['55','2','3','0','21','132'....]; //real values

monthyear数组排序时,我希望此数组中的数据根据​​monthyear位置移动到新位置。像这样:

Desired Array1: [....'Apr18','May18','Jun18','Jul18','Jan19','Mar19'];
Desired Array2: [....'Apr18_value','May18_value','Jun18_value','Jul18_value','Jan19_value','Mar19_value'];

所以我可以像以后一样选择数据:

var label = array[4];
var value = array2[4];

如何实现这一目标?

javascript html arrays sorting
9个回答
12
投票

您可以将日期作为可排序字符串并对其进行排序。

为了获得按一个签名数组排序的多个数组,您可以使用map进行排序,您可以在其中对索引数组进行排序,指示最终排序,然后使用此排序重新分配所有数组。

getD函数通过获取array0的索引进行排序来返回格式化的字符串。在函数内部,字符串被破坏为月份和年份部分,并由其ISO 8601表示替换。替换函数回调获取匹配的项目,返回具有格式化年份的数组以及具有月份名称和相关月份编号的对象的月份。然后,连接并返回此数组。

排序与String#localeCompare进行比较。

var array1 = ['Mar19', 'Apr18', 'Jun18', 'Jul18', 'May18', 'Jan19'],
    array2 = ['Mar19_value', 'Apr18_value', 'Jun18_value', 'Jul18_value', 'May18_value', 'Jan19_value'],
    array3 = ['55', '2', '3', '0', '21', '132'],
    indices = Object
        .keys(array1)
        .sort(function (a, b) {
            function getD(i) {
                var months = { Jan: '01', Feb: '02', Mar: '03', Apr: '04', May: '05', Jun: '06', Jul: '07', Aug: '08', Sep: '09', Oct: '10', Nov: '11', Dec: '12' },
                    s = array1[i];
                return s.replace(/^(...)(.+)$/, (_, m, y) => [y.padStart(4, '0'), months[m]].join('-'));
            }
            return getD(a).localeCompare(getD(b));
        }),
    result = [array1, array3].map(a => indices.map(i => a[i]));
  
result.forEach(a => console.log(...a));

13
投票

你需要将字符串更改为new Date(dateString) format之类的

new Date(Month Date Year)

更新了两个阵列的正则表达式模式

https://regex101.com/r/h1cm1z/2/

基于第一个数组排序索引更新了Sort Second数组

var arr1 =  ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'];
var arr2 =['55','2','3','0','21','132'];

function datesort(arr){
 return arr.concat().sort((a,b)=>{
 a = a.replace(/(\d+)(.*)/g,' 1 $1'); // Month 1 YEAR
 b = b.replace(/(\d+)(.*)/g,' 1 $1'); // Month 1 YEAR
  return new Date(a) - new Date(b)
})
}

var after_arr1 =new datesort(arr1);
var after_arr2 = arr1.reduce(function(a,b,c){
     var ind = after_arr1.indexOf(b);
     a[ind] = arr2[c]
     return a
},[]);


console.log(after_arr1.join(','));
console.log(after_arr2.join(','))

9
投票

要正确订购,您需要知道月份的顺序。这不是按字母顺序排列的,因此您可以使用具有月份顺序的数组,然后查找它们。

const monthOrder = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec “]

已经正确排序,可以与.indexOf()一起使用,以获得一个月的位置。

const myArr =  ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'];
const myArr2 = ['Mar19_value','Apr18_value','Jun18_value','Jul18_value','May18_value'
   ,'Jan19_value'];

const monthOrder = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

let sortYearMonth = (a, b) => {
    let monthA = monthOrder.indexOf(a.slice(0,3))
	let yearA = a.slice(3,6)
	let monthB = monthOrder.indexOf(b.slice(0,3))
	let yearB = b.slice(3,6)
	return (`${yearA}-${monthA}` < `${yearB}-${monthB}`) ? -1 : (`${yearA}-${monthA}` > `${yearB}-${monthB}`) ? 1 : 0
}

let sortedMonths = myArr.sort(sortYearMonth)
let sortedMonths2 = myArr2.sort(sortYearMonth)

console.log(sortedMonths )
console.log(sortedMonths2 )

更新:相同位置的值

更新后的版本将两个数组链接在一起,然后对第一个进行排序,同时将相对位置保持为第二个。

想法:使用临时对象链接两个数组,然后使用Object.entries提取键/值对。然后根据对的第一个值(即array1的值)对数组进行排序。然后它以正确的顺序返回键/值对,您可以使用.map()再次将值提取到两个数组中

我添加了一个带有基于字符串的示例和下面的实际值示例的运行

const myArr = ['Mar19', 'Apr18', 'Jun18', 'Jul18', 'May18', 'Jan19'];
const myArr2 = ['Mar19_value', 'Apr18_value', 'Jun18_value', 'Jul18_value', 'May18_value', 'Jan19_value'];

const myArr3 = ['55','2','3','0','21','132'];

const monthOrder = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

let sortYearMonth = (a, b) => {
  let monthA = monthOrder.indexOf(a.slice(0, 3))
  let yearA = a.slice(3, 6)
  let monthB = monthOrder.indexOf(b.slice(0, 3))
  let yearB = b.slice(3, 6)
  return (`${yearA}-${monthA}` < `${yearB}-${monthB}`) ? -1 : (`${yearA}-${monthA}` > `${yearB}-${monthB}`) ? 1 : 0
}

function sortByFirst(myArr, myArr2) {
  let keyValue = myArr.reduce((links, item, i) => {
    links[item] = myArr2[i];
    return links
  }, {})
  let entries = Object.entries(keyValue)
  return entries.sort((a, b) => sortYearMonth(a[0], b[0]))
}

let sortedEntries = sortByFirst(myArr, myArr2)
let sortedMonths = sortedEntries.map(i => i[0])
let sortedValues = sortedEntries.map(i => i[1])

let sortedEntries2 = sortByFirst(myArr, myArr3)
let sortedMonths2 = sortedEntries2.map(i => i[0])
let sortedValues2 = sortedEntries2.map(i => i[1])

console.log(sortedMonths)
console.log(sortedValues)

console.log(sortedMonths2)
console.log(sortedValues2)

9
投票

const input = ['Mar19', 'Apr18', 'Jun18', 'Jul18', 'May18', 'Jan19'];

//const output : ['Apr18','May18','Jun18','Jul18','Jan19','Mar19'];
//Can be done easily by using momentjs, darte-fns, but here i will do it natively

const t = {
  Jan: 1,
  Feb: 2,
  Mar: 3,
  Apr: 4,
  May: 5,
  Jun: 6,
  Jul: 7,
  Aug: 8,
  Sep: 9,
  Oct: 10,
  Nov: 11,
  Dec: 12
}
const giveConcatString = (a, t) => {
  const monthPart = a.substr(0, 3)
  const yearPart = a.substr(3)
  return `${yearPart}${t[monthPart]}`
}
const sortedArray = input.sort((a, b) => {
  const concatString = giveConcatString(a, t)
  const concatStringB = giveConcatString(b, t)
  return concatString <= concatStringB ? -1 : 1

})
console.log(sortedArray)

这可以帮助您解决此问题。它是原生的吗?


4
投票

你可以尝试这个原始片段。

var MY = ['Mar19', 'Apr18', 'Jun18', 'Jul18', 'May18', 'Jan19'];
var s = "JanFebMarAprMayJunJulAugSepOctNovDec";
// converting to raw date format
for (i in MY) {
  num = MY[i].match(/\d+/g);
  letr = MY[i].match(/[a-zA-Z]+/g);
  MY[i] = (s.indexOf(letr) / 3 + 1) + '-' + '20' + num;
}
// sorting logic
var sorted = MY.sort(function(a, b) {
  a = a.split("-");
  b = b.split("-")
  return new Date(a[1], a[0], 1) - new Date(b[1], b[0], 1)
});
// converting back to original array after sorting
res = [];
for (i in sorted) {
  var a = sorted[i].split('-');
  res[i] = (s.substr((parseInt(a[0]) - 1) * 3, 3)) + '-' + a[1].substr(2, 2);
}

console.log(res);

3
投票

我使用lodash进行排序,并使用substring方法将日期分为月份和日期部分

const data = ['Mar20','Mar21', 'Mar01', 'Mar19','Apr18','Jun18','Jul18','May18','Jan19']

const monthMap = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

const sorted = _.sortBy(data, date => monthMap.indexOf(date.substring(0,3)), date => date.substring(3,5))

console.log(sorted)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

3
投票
let mth = ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'];

mth.sort((itemA, itemB)=>{
   let mthAstr = itemA.slice(0,3)+" 01 "+itemA.slice(3,5);
   let mthA = new Date(mthAstr);
   let mthBstr = itemB.slice(0,3)+" 01 "+itemB.slice(3,5);
   let mthB = new Date(mthBstr);
   if (mthA < mthB)
      return -1;
   if (mthA > mthB)
      return 1;
   return 0;
});

3
投票

你可以试试这样的东西:

var Array =  ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'];
Array.sort(function(a, b) {
    a = [a.slice(0,3), ' 20', a.slice(3)].join('');
    b = [b.slice(0,3), ' 20', b.slice(3)].join('')
    return new Date() - new Date(b);
});

console.log(Array);

2
投票

我建议您的数据结构是不幸的。使用共享索引比使用它们的数据结构(例如对象数组[{label: 'Mar19', value: 55}, ...])要困难得多。

如果您的数据来自您无法控制的上游解决方案,您仍可以在自己的工作中进行管理,在使用之前进行转换。 (如果你真的不得不转回去传递给别人。)

组合两个数组的函数的通用名称是zip - 认为它像拉链一样。此版本使用一个函数来说明应如何组合配对元素。 (在其他地方,这样的功能可能被称为zipWith。)

在这里,sortArraysByDatezip通过一个函数将'Mar19'55变成{label: 'Mar19, value: 55, month: 'Mar', year: 19},使用dateFields从该标签中提取月份和年份,然后使用简单的dateSort对这些进行排序

const months = {Jan: 1, Feb: 2, Mar: 3, Apr: 4,  May: 5,  Jun: 6,
                Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12}
                
const dateFields = (d) => ({
  month: d.slice(0, 3),
  year: Number(d.slice(3))
})

const dateSort = ({month: m1, year: y1}, {month: m2, year: y2}) =>
  (y1 - y2) || (months[m1] - months[m2])

const zip = (fn, a1, a2) => a1.map((a, i) => fn(a, a2[i]))

const sortArraysByDate = (a1, a2) =>
  zip((label, value) => ({label, value, ...dateFields(label)}), a1, a2)
    .sort(dateSort)
    .map(({label, value}) => ({label, value}))


const Array1 = ['Mar19','Apr18','Jun18','Jul18','May18','Jan19'];
const Array2 =   ['55','2','3','0','21','132']; //real values

const result = sortArraysByDate(Array1, Array2)

console.log(result)

mapsortArraysByDate呼叫很可能没有必要。没有它,结果数据包括额外的yearmonth字段;这可能不是问题。

如果你真的需要原始格式的更新数组,你可以只需map结果:

const newArray1 = result.map(o => o.label)
const newArray2 = result.map(o => o.value)

但我会敦促你不要这样做,除非绝对必要。这种结构非常有用。配对阵列要少得多。

此外,如果您需要组合两个以上的数组,您可以编写更复杂的zip版本:

const zip = (fn, ...as) => as[0].map((_, i) => fn(...as.map(a => a[i])))

这将在n参数和n数组上执行一个函数,并生成一个新数组,其中包含分别在每个数组中的连续项上调用该函数的结果。

© www.soinside.com 2019 - 2024. All rights reserved.