3

I have two arrays in Javascript coming from Php. I merge these arrays into one array.

All of arrays' elements has created_at value (Laravel). I want to sort these values by created_at

Problem: Regardless of their date. First array's elements never take place in behind of those of second array

Example: B has latest date. But even so, C (comes from second array) takes place after B.

The problem is although I merged these two arrays into one array. Javascript still thinks "there are two arrays. I should sort first array's elements then those of second array."

What do I do is :

history.push(...response.data[0]); // first array's values
history.push(...response.data[1]); // second array's values

history.sort((a, b) => {
            return a.created_at - b.created_at;
          });

so, history like

[

// Comes from first array

 {
  name: 'A',
  created_at: '08/09/2021'
 },

// Comes from first array

{
  name: 'B',
  created_at: '15/09/2021'
 },


// This third element comes from second array.

{
  name: 'C',
  created_at: '08/09/2021'
 }
]

I expect this result:

new sorted history:


 {
  name: 'A',
  created_at: '08/09/2021'
 },

{
  name: 'C',
  created_at: '08/09/2021'
 },

{
  name: 'B',
  created_at: '15/09/2021'
 }



But Javascript initially sorts first array's element. After, sort second array's element then what comes out is:


 {
  name: 'A',
  created_at: '08/09/2021'
 },

{
  name: 'B',
  created_at: '15/09/2021'
 },
{
  name: 'C',
  created_at: '08/09/2021'
 },

11
  • 3
    The order of elements is exactly how you add them to the array. If you want to sort the array then you have to explicitly do that. Commented Sep 8, 2021 at 19:01
  • Are you need to sort your array by date ?? Commented Sep 8, 2021 at 19:03
  • You never called history.sort(). Why are you expecting them to be reordered? Commented Sep 8, 2021 at 19:12
  • After you merge both of your arrays you need to sort it ` history.sort((r1, r2) => { d1 = new Date(r1.created_at); d2 = new Date(r2.created_at); return d1 > d2 ? 1 : (d1 < d2 ? -1 : 0)}) ` Commented Sep 8, 2021 at 19:17
  • JavaScript doesn't automatically sort array elements upon insertion. Don't confuse the notion of ordered set and sorted set. Commented Sep 8, 2021 at 19:21

3 Answers 3

4

You can array#concat both your array and use Schwartzian transform to sort your array by converting the created_at to YYYY-MM-DD format which could be sorted lexicographically.

const arr1 = [{name: 'A', created_at: '08/09/2021'}],
      arr2 = [{name: 'B', created_at: '15/09/2021'}, {name: 'C', created_at: '08/09/2021'}],
      result = arr1.concat(arr2)
                   .map(o => [o.created_at.replace(/(..)\/(..)\/(....)/, '$3-$2-$1'), o])
                   .sort((a,b) => a[0].localeCompare(b[0]))
                   .map(([,o]) => o);
console.log(result)

Sign up to request clarification or add additional context in comments.

2 Comments

@HassanImam Can you explain or recommend some things about Schwartzian Transform. I have looked some sites but I didn't understand.
It is similar to decorate, sort and undecorate. In the decorate step, we create an array of original object and transformed date, which we will use during sorting, it helps us in avoiding multiple date conversion. Once sorted, we return the original object using array#map.
1

You need to send a custom sort function to Array.sort()

const array = 
[
    { name: 'A', created_at: '08/09/2021' },
    { name: 'B', created_at: '15/09/2021' },
    { name: 'C', created_at: '08/09/2021' }
];

const ymd = (dmy) => { let a = dmy.split('/'); return a[2] + '/' + a[1] + '/' + a[0] }

const sorted = array.sort((elem1, elem2) => ymd(elem1.created_at) > ymd(elem2.created_at) ? 1 : -1);
console.log(sorted);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Edit:

If you need the sort to be stable (meaning it does not ever arbitrarily swap objects with equivalent comparison values) or by date first and alpha second, then you will need a more complex sort function.

With a little more time and a localeCompare() suggestion form Felix Kling I wrote an improved sort that is stable and will sort by date first and name second.

const array =
    [
        { name: 'A', created_at: '08/09/2021' },
        { name: 'Z', created_at: '15/09/2021' },
        { name: 'D', created_at: '15/09/2021' },
        { name: 'B', created_at: '15/09/2021' },
        { name: 'C', created_at: '08/09/2021', stable: '1'},
        { name: 'S', created_at: '08/09/2020' },
        { name: 'C', created_at: '08/09/2021', stable: '2' },
        { name: 'C', created_at: '08/06/2021' }
    ];

const ymd = (dmy) => { let a = dmy.split('/'); return a[2] + '/' + a[1] + '/' + a[0] }

const sorted = array.sort((elem1, elem2) =>
    (ymd(elem1.created_at) === ymd(elem2.created_at)) ?
        elem1.name.localeCompare(elem2.name) :
        ymd(elem1.created_at).localeCompare(ymd(elem2.created_at)));

console.log(sorted);

Outputs:

[
  { name: 'S', created_at: '08/09/2020' },
  { name: 'C', created_at: '08/06/2021' },
  { name: 'A', created_at: '08/09/2021' },
  { name: 'C', created_at: '08/09/2021', stable: '1' },
  { name: 'C', created_at: '08/09/2021', stable: '2' },
  { name: 'B', created_at: '15/09/2021' },
  { name: 'D', created_at: '15/09/2021' },
  { name: 'Z', created_at: '15/09/2021' }
]

2 Comments

You are not account for the case where both dates are equal (and should return 0 from the callback). Use ymd(elem1.created_at).localeCompare(ymd(elem2.created_at)) to simplify the comparison. But you are the only one so far that accounts for the original date format not being sortable.
You are correct, there should be a stable sort (0) and likely alphabetical by name too, which is why I mentioned that. I will try to improve it now that I have some time.
0

To sort by date values you can use Date.prototype.getTime():

const arr1 = [{name: 'A', created_at: '08/09/2021'}]
const arr2 = [{name: 'B', created_at: '15/09/2021'}, {name: 'C', created_at: '08/09/2021'}]

const toNumber= d => +d.replace(/\//g, '')
const result =  [...arr1, ...arr2].sort((a, b) => toNumber(a.created_at) - toNumber(b.created_at))

console.log(result)

5 Comments

Why should it be incorrect? It's just that Date can't handle that format. localeCompare won't work, try "22/01/2021" for one of the dates.
You should explain that you changed the date format and why you did it.
The format in your date is wrong.. You should try new Date('15/09/2021') and you will see the error
It's not my date. I didn't ask the question. You keep saying that the format is "wrong": Dates can be formatted in various ways. Only because Date cannot handle the format doesn't mean dd/mm/yyy is "wrong". There are countries who use this format: en.wikipedia.org/wiki/Date_format_by_country
You're welcome. I could have been clearer about why the date format is not "incorrect".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.