Сортировать массив по месяцам и годам - PullRequest
19 голосов
/ 08 марта 2019

Мне нужна помощь в сортировке массива по месяцам и годам для отображения на графике соответственно.

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];

Как это можно сделать?

Ответы [ 9 ]

13 голосов
/ 08 марта 2019

Вам нужно изменить строку на new Date(dateString) формат как

new Date(Month Date Year)

Обновленный шаблон регулярных выражений для обоих массивов

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

Обновлено Сортировать второй массив на основе индекса сортировки первого массива

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(','))
12 голосов
/ 08 марта 2019

Вы можете получить дату в виде сортируемой строки и отсортировать ее.

Для получения более одного массива, отсортированного по одному массиву сигнатур, вы можете выполнить сортировку по карте, где вы сортируете массив индексов, указывающих окончательную сортировку, а затем переназначаете все массивы с помощью этой сортировки.

Функция 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));
9 голосов
/ 08 марта 2019

Для правильного оформления заказа необходимо знать порядок месяцев. Это не в алфавитном порядке, поэтому вы можете использовать массив с порядком месяцев, а затем искать их.

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 голосов
/ 08 марта 2019

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 голосов
/ 08 марта 2019

Вы можете попробовать этот необработанный фрагмент.

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 голосов
/ 08 марта 2019

Вы можете попробовать что-то вроде этого:

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);
3 голосов
/ 08 марта 2019
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 голосов
/ 08 марта 2019

Я использовал 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>
2 голосов
/ 08 марта 2019

Я бы предположил, что ваша структура данных неудачна. Работа с общими индексами делает это намного сложнее, чем структура данных, которая их объединяет, например, массив объектов [{label: 'Mar19', value: 55}, ...].

Если ваши данные поступают из вышестоящего решения, которое вы не можете контролировать, вы все равно можете управлять им в своей работе, конвертируя перед использованием. (И если вам действительно нужно обратиться обратно, чтобы передать другим.)

Общее имя функции, объединяющей два массива: zip - представьте, что она действует как молния. Эта версия использует тот, который принимает функцию, чтобы сказать, как парные элементы должны быть объединены. (В других местах такая функция может называться zipWith.)

Здесь sortArraysByDate вызывает zip, передавая функцию, которая превращает '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)

Вызов map в sortArraysByDate вполне возможен. Без него результирующие данные включают в себя дополнительные поля year и month; это может не быть проблемой.

Если вам действительно нужны эти обновленные массивы в исходном формате, вы можете просто 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 массивов и выдает новый массив, содержащий результат вызова этой функции соответственно для последовательных элементов в каждом из массивов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...