skip to Main Content

I have a list of strings that I want to use as duration filter options. They are currently sorted alphabetically but I want them to be sorted by length of time. Is this possible?

The strings are:

['1 day', '2 days', '2 weeks', '3 days', '3 hours', '4 days']

What I want is:

['3 hours', '1 day', '2 days', '3 days', '4 days', '2 weeks']

Currently i’m sorting them alphabetically by:

const durations = [...new Set(this.courses.map(item => item.fields.duration).sort((a, b) => a.localeCompare(b)))];

5

Answers


  1. First, create a method to convert the list to the minimum time period which is hours,
    For example

    1. 1 day = 24 hours
    2. 1 week = 24 * 7 hours
    const convertToHours = (duration) => {
      const [value, unit] = duration.split(' ');
      const num = parseInt(value, 10);
    
      switch (unit) {
        case 'hour':
        case 'hours':
          return num;
        case 'day':
        case 'days':
          return num * 24;
        case 'week':
        case 'weeks':
          return num * 24 * 7;
        default:
          return num;
      }
    };
    
    

    Then sort the list by comparing the result of convertToHours method.

    const sortedDurations = durations.sort((a, b) => convertToHours(a) - convertToHours(b));
    

    This is working codesnippet

    const durations = ['1 day', '2 days', '2 weeks', '3 days', '3 hours', '4 days'];
    
    const convertToHours = (duration) => {
      const [value, unit] = duration.split(' ');
      const num = parseInt(value, 10);
    
      switch (unit) {
        case 'hour':
        case 'hours':
          return num;
        case 'day':
        case 'days':
          return num * 24;
        case 'week':
        case 'weeks':
          return num * 24 * 7;
        default:
          return num;
      }
    };
    
    
    const sortedDurations = durations.sort((a, b) => convertToHours(a) - convertToHours(b));
    
    console.log(sortedDurations);

    You can use regular expressions for extracting the value and unit in case there are extra spaces/new lines /(d+)s*(w+)/.

    const durations = ['1  day', '2 daysn', '2 n weeks', '3 days', '3 hours', '4 days'];
    
    const convertToHours = (duration) => {
      const match = duration.match(/(d+)s*(w+)/);
      if (!match) return 0;
    
      const num = +match[1];
      const unit = match[2];
    
      switch (unit) {
        case 'hour':
        case 'hours':
          return num;
        case 'day':
        case 'days':
          return num * 24;
        case 'week':
        case 'weeks':
          return num * 24 * 7;
        default:
          return num;
      }
    };
    
    
    const sortedDurations = durations.sort((a, b) => convertToHours(a) - convertToHours(b));
    
    console.log(sortedDurations);
    Login or Signup to reply.
  2. AFAIK you can not parse those "range-strings" into a comparable format with vanilla-js itself, you could however write some code that does so, or use a library that can do this somehow, in example dayjs

    Personally i would just blow up the inital array with comparable data, something like:

    [
      {
        label: '1 day',
        hours: 24
      },
      {
        label: '2 days',
        hours: 48
      },
      {
        label: '3 hours',
        hours: 3
      }
    ]
    

    And then you would sort for hours and only display label

    Login or Signup to reply.
  3. To sort the durations by length of time, you can convert each duration to a common unit (like hours) and sort based on that. Here’s how you can do it:

    const durations = ['1 day', '2 days', '2 weeks', '3 days', '3 hours', '4 days'];
    
    const durationsInHours = durations.map(duration => {
      const [value, unit] = duration.split(' ');
      switch (unit) {
        case 'hour':
        case 'hours':
          return { duration, value: Number(value) };
        case 'day':
        case 'days':
          return { duration, value: Number(value) * 24 };
        case 'week':
        case 'weeks':
          return { duration, value: Number(value) * 24 * 7 };
        default:
          return { duration, value: 0 };
      }
    });
    
    const sortedDurations = durationsInHours.sort((a, b) => a.value - b.value).map(item => item.duration);
    
    console.log(sortedDurations);
    

    This code first maps each duration to an object that contains the original duration string and its equivalent value in hours. Then it sorts these objects based on the value in hours, and finally maps the sorted objects back to an array of duration strings.

    Login or Signup to reply.
  4. There are several ways to achieve that result.. one is converting those durations to scalar using a common unit (hours in this case) so that they will be comparable for the sake of sorting.

    In this demo I have a function that convert the duration given as string to scalar as the equivalent amount of hours that will be used in the sort callback function to decide which one comes first in the sort order.

    I see other answers came before this one.. I guess this one doesn’t add that much.

    const data = ['1 day', '2 days', '2 weeks', '3 days', '3 hours', '4 days'];
    
    function timeToHours(time){
    
      const units = {hour: 1, day: 24, week: 24*7};
    
      const parts = time.match(/^(d+)s(hour|day|week)s?$/);
      if (!parts)
        throw new Error(`'${time}' - Unexpected time format`);  
      const scalar = parseInt(parts[1]);
      const hours = units[parts[2]];
    
      return hours*scalar;
    }
    
    try {
      const sorted = data.sort((a, b) => timeToHours(a) - timeToHours(b)); 
      console.log(sorted);
      /*
      =>
        [
          "3 hours",
          "1 day",
          "2 days",
          "3 days",
          "4 days",
          "2 weeks"
        ]
      */
    } catch (error) {
      console.log(`error occurred! - ${error}`);
    }
    Login or Signup to reply.
  5. For every type of time hour, day and week I assign the equivalent number of minutes and I use it to create a map to assign a value to every time in array, in order to sort it on value calculated.

    const minutes = {
        h: 60,
        d: 1440,
        w: 10080,
        m: 43800
    }
    
    const durationsStrings = ['1 day', '2 days', '2 weeks', '3 days', '1 hours', '4 days']
    
    console.log((durationsStrings.map(item => {
        return {
        "value": item.split(" ")[0]*minutes[item.split(" ")[1].charAt(0)],
        "duration": item
    }}).sort((a, b) => a.value - b.value)).map(item => item.duration))
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search