skip to Main Content

I have a 2D array in JavaScript where the first row contains date-time strings, and I want to sort all the rows based on the dates in the first row. Here’s an example of my array:

const data = [
  ['4:23:28 PM', '4:24:01 PM', '4:24:39 PM', '4:26:05 PM'],
  [1, 2, 3, 0],
  [4, 5, 3, 2]
];

I’ve tried a few approaches, but I’m running into issues. Can someone provide a working solution or suggest how I can achieve this? Also, here’s the expected output after sorting:

const expectedOutput = [
  ['4:26:05 PM', '4:24:39 PM', '4:24:01 PM', '4:23:28 PM'],
  [0, 3, 2, 1],
  [2, 3, 5, 4]
];


Thank you in advance for your help!

4

Answers


  1. you first need to convert (map) the date you have in each item to a sortable item … here is the approach I usually used

    const data = [
      ['4:23:28 PM', '4:24:01 PM', '4:24:39 PM', '4:26:05 PM'],
      [1, 1, 1, 1],
      [1, 1, 1, 1]
    ];
    
    // Create a function to convert date-time strings to timestamps
    const toTimestamp = (dateTimeString) =>
      new Date(`1970-01-01 ${dateTimeString}`).getTime();
    
    data.sort((a, b) => {
      const timestampA = toTimestamp(a[0]);
      const timestampB = toTimestamp(b[0]);
      return timestampB - timestampA; // descending sort
    });
    
    Login or Signup to reply.
  2. You can do this in steps:

    • Transpose the 2D array
    • Sort the rows by their first member. To compare those time strings, parse them into a number of seconds since midnight
    • Transpose the sorted 2D array

    Here is how it could be done:

    const transpose = arr => arr[0].map((_, i) => arr.map(row => row[i]));
    const timeOf = str => // Parse "h:mm:ss am" format
        ((h,m,s,p) => ((h % 12) + (p > 'P') * 12) * 3600 + m * 60 + +s)
            (...str.match(/w+/g));
    
    const data = [
      ['4:23:28 PM', '4:24:01 PM', '4:24:39 PM', '4:26:05 PM'],
      [1, 2, 3, 0],
      [4, 5, 3, 2]
    ];
    const result = transpose(
                      transpose(data)
                      .sort(([a], [b]) => timeOf(b) - timeOf(a)) // reversed
                   );
    console.log(result);
    Login or Signup to reply.
  3. Here’s an approach

    const data = [
        ["4:23:28 PM", "4:24:01 PM", "4:24:39 PM", "4:26:05 PM"],
        [1, 2, 3, 0],
        [4, 5, 3, 2],
    ];
    
    const getDate = (timeString) => {
      const [time, ampm] = timeString.split(' ');
      const [hours, minutes, seconds] = time.split(':').map(Number);
      const adjustedHours = ampm === 'PM' && hours !== 12 ? hours + 12 : hours;
      return new Date(0, 0, 0, adjustedHours, minutes, seconds);
    };
    
    const sortedIndices = data[0]
        .map((time, index) => [index, getDate(time)])
        .sort((a, b) => b[1] - a[1])
        .map(([index]) => index);
        
    const transformed = data.map((arr) => sortedIndices.map((index) => arr[index]));
    
    console.log(transformed);
    Login or Signup to reply.
  4. const data = [
      ['4:23:28 PM', '4:24:01 PM', '4:24:39 PM', '4:26:05 PM'],
      [1, 2, 3, 0],
      [4, 5, 3, 2]
    ];
    
    const transformTime = a => a.slice(0,2) === '12' ? 
      (a[a.length - 2] === 'A' ? 'P12' : 'A00') + a.slice(2) : 
      a[a.length - 2] + a.padStart(11, '0');
      
    const sortedTime = data[0]
      .map((time, idx) => ({time: transformTime(time), idx}))
      .sort(({time: a}, {time: b}) => a < b ? 1 : a === b ? 0 : -1)
      .map(({idx}) => idx);
    
    const result = data.map(arr => sortedTime.map(idx => arr[idx]));
    
    result.forEach(arr=>console.log(...arr.map(JSON.stringify)));

    And a benchmark:

    Cycles: 100000 / Chrome/116
    ------------------------------------------------------
    Alexander        39/min  1.0x   39   39   58   47   46
    trincot         118/min  3.0x  127  118  123  133  143
    Abito Prakash   207/min  5.3x  209  207  218  218  228
    ------------------------------------------------------
    https://github.com/silentmantra/benchmark
    
    <script benchmark="100000">
    
    const data = [
      ['4:23:28 PM', '4:24:01 PM', '4:24:39 PM', '4:26:05 PM'],
      [1, 2, 3, 0],
      [4, 5, 3, 2]
    ];
    
    
    // @benchmark Abito Prakash
    const getDate = (timeString) => {
      const [time, ampm] = timeString.split(' ');
      const [hours, minutes, seconds] = time.split(':').map(Number);
      const adjustedHours = ampm === 'PM' && hours !== 12 ? hours + 12 : hours;
      return new Date(0, 0, 0, adjustedHours, minutes, seconds);
    };
    
    const sortedIndices = data[0]
        .map((time, index) => [index, getDate(time)])
        .sort((a, b) => b[1] - a[1])
        .map(([index]) => index);
        
    data.map((arr) => sortedIndices.map((index) => arr[index]));
    
    // @benchmark trincot
    const transpose = arr => arr[0].map((_, i) => arr.map(row => row[i]));
    const timeOf = str => // Parse "h:mm:ss am" format
        ((h,m,s,p) => ((h % 12) + (p > 'P') * 12) * 3600 + m * 60 + +s)
            (...str.match(/w+/g));
    
    
    transpose(
                      transpose(data)
                      .sort(([a], [b]) => timeOf(b) - timeOf(a)) // reversed
                   );
    
    // @benchmark Alexander
    
    const transformTime = a => a.slice(0,2) === '12' ? 
      (a[a.length - 2] === 'A' ? 'P12' : 'A00') + a.slice(2) : 
      a[a.length - 2] + a.padStart(11, '0');
    const sortedTime = data[0].map((time, idx) => ({time: transformTime(time), idx})).sort(({time: a}, {time: b}) => a < b ? 1 : a === b ? 0 : -1).map(({idx}) => idx);
    data.map(arr => sortedTime.map(idx => arr[idx]));
    
    </script>
    <script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search