按属性对三个不同的对象数组进行排序

时间:2019-05-15 11:09:10

标签: javascript arrays typescript

我需要在Date字段上对三个不同的对象数组进行排序,其中该字段在每个组中都有不同的名称。

下面是我的数据示例:

const documents = [
{
    documentId: 'ADB0125A',
    fileName: 'test_2018.pdf',
    date': '2017-12-02T19:08:52+01:00'  // Field to sort by
},
{
    documentId: '123456',
    fileName: 'test2_2018.pdf',
    date': '2017-12-12T22:08:52+01:00'  // Field to sort by
},
{
    documentId: '121212',
    fileName: 'test3_2018.pdf',
    date': '2018-05-22T23:08:52+01:00'  // Field to sort by
}];

const conversations = [
{
    conversationId: '1102',
    lastUpdate: '2015-10-10T18:19:12+01:00'  // Field to sort by
},
{
    conversationId: '5622',
    lastUpdate: '2019-08-16T18:19:12+01:00'  // Field to sort by
},
{
    conversationId: '112',
    lastUpdate: '2015-10-26T18:19:12+01:00'  // Field to sort by
}];

const invoices = [
{
    invoiceId: "20100392077",
    rechnungsDatum: "2019-02-10"  // Field to sort by
},
{
    invoiceId: "5550392077",
    rechnungsDatum: "2018-02-05"  // Field to sort by
},
{
    invoiceId: "3336392077",
    rechnungsDatum: "2018-12-11"  // Field to sort by
}];

目标:返回最后4个结果(一旦我列出了.reverse()的最终集合,我就可以用ASC获得结果),与它们来自哪个来源无关。我希望得到:

const result = [
    {
        conversationId: '5622',
        lastUpdate: '2019-08-16T18:19:12+01:00'
    },
    {
        invoiceId: "20100392077",
        rechnungsDatum: "2019-02-10"
    },
    {
        invoiceId: "3336392077",
        rechnungsDatum: "2018-12-11"
    },
    {
        documentId: '121212',
        fileName: 'test3_2018.pdf',
        date': '2018-05-22T23:08:52+01:00'
    }
]

是否可以对所有三个对象使用唯一的Array.sort方法,或者唯一的方法是成对比较它们并根据部分结果构建结果?

6 个答案:

答案 0 :(得分:4)

您可以使用一个对象,该对象具有通缉日期属性的replacemnt键和一个平面数组,该数组保留了源和归一化日期属性,对数组进行排序并返回顶部的四个元素。

最后,删除不必要的信息并检索原始对象结构。

const
    documents = [{ documentId: 'ADB0125A', fileName: 'test_2018.pdf', date: '2017-12-02T19:08:52+01:00' }, { documentId: '123456', fileName: 'test2_2018.pdf', date: '2017-12-12T22:08:52+01:00' }, { documentId: '121212', fileName: 'test3_2018.pdf', date: '2018-05-22T23:08:52+01:00' }],
    conversations = [{ conversationId: '1102', lastUpdate: '2015-10-10T18:19:12+01:00' }, { conversationId: '5622', lastUpdate: '2019-08-16T18:19:12+01:00' }, { conversationId: '112', lastUpdate: '2015-10-26T18:19:12+01:00' }],
    invoices = [{ invoiceId: "20100392077", rechnungsDatum: "2019-02-10" }, { invoiceId: "5550392077", rechnungsDatum: "2018-02-05" }, { invoiceId: "3336392077", rechnungsDatum: "2018-12-11" }]
    keys = { documents: 'date', conversations: 'lastUpdate', invoices: 'rechnungsDatum' },
    result = Object
        .entries({ documents, conversations, invoices })
        .reduce((r, [k, v]) => [...r, ...v.map(payload => ({ payload, date: payload[keys[k]] }))], [])
        .sort((a, b) => b.date.localeCompare(a.date))
        .slice(0, 4)
        .map(({ payload }) => payload);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

您可以按照以下步骤进行操作:

  • 首先使用嵌套的map()添加另一个名为key的属性,其值将是需要对该对象进行排序的值。
  • 然后使用flat()制作一维数组
  • 然后根据我们在地图中添加的键的值,先应用sort(),然后再应用sort()

const documents = [ { documentId: 'ADB0125A', fileName: 'test_2018.pdf', date: '2017-12-02T19:08:52+01:00' }, { documentId: '123456', fileName: 'test2_2018.pdf', date: '2017-12-12T22:08:52+01:00' }, { documentId: '121212', fileName: 'test3_2018.pdf', date: '2018-05-22T23:08:52+01:00' }]; const conversations = [ { conversationId: '1102', lastUpdate: '2015-10-10T18:19:12+01:00' }, { conversationId: '5622', lastUpdate: '2019-08-16T18:19:12+01:00' }, { conversationId: '112', lastUpdate: '2015-10-26T18:19:12+01:00' }]; const invoices = [ { invoiceId: "20100392077", rechnungsDatum: "2019-02-10" }, { invoiceId: "5550392077", rechnungsDatum: "2018-02-05" }, { invoiceId: "3336392077", rechnungsDatum: "2018-12-11" }];


let keys = ['date','lastUpdate','rechnungsDatum'];


const res = [documents,conversations,invoices]
                         .map((x,i) => x.map(a => (
                               {...a,key:a[keys[i]]}))
                        ).flat()
                         .sort((a,b) => a.key.localeCompare(b.key))
                         .slice(-4)
                         .reverse()
                         .map(({key,...rest}) => rest)
                          
console.log(res)

答案 2 :(得分:1)

您可以使用 WeakMap 存储对应该对数组进行排序的对象属性的引用,并使用存储的属性简单地查找值。

const flatten = (flat, arr) => [...flat, ...arr];
const PropMap = (props, arrs) => {
	let map = new WeakMap();
	for (let i=-1, arr; arr = arrs [++i];)
        for (let j=0, obj; obj = arr [j++];)     
             map.set (obj, props [i])
    return map;
}
PropMap.SortBy = map => (a,b) => {
   let [l, r] = [a,b].map (obj => obj [map.get (obj)])
   return l>r?-1:l<r?1:0
}

const data = [documents, conversations, invoices];
const props = ["date", "lastUpdate", "rechnungsDatum"]
const map = PropMap (props,data);

console.log (
  data.reduce (flatten, []).sort (PropMap.SortBy (map)).slice (0,4)
)
    
    
    
<script>
const
    documents = [{ documentId: 'ADB0125A', fileName: 'test_2018.pdf', date: '2017-12-02T19:08:52+01:00' }, { documentId: '123456', fileName: 'test2_2018.pdf', date: '2017-12-12T22:08:52+01:00' }, { documentId: '121212', fileName: 'test3_2018.pdf', date: '2018-05-22T23:08:52+01:00' }],
    conversations = [{ conversationId: '1102', lastUpdate: '2015-10-10T18:19:12+01:00' }, { conversationId: '5622', lastUpdate: '2019-08-16T18:19:12+01:00' }, { conversationId: '112', lastUpdate: '2015-10-26T18:19:12+01:00' }],
    invoices = [{ invoiceId: "20100392077", rechnungsDatum: "2019-02-10" }, { invoiceId: "5550392077", rechnungsDatum: "2018-02-05" }, { invoiceId: "3336392077", rechnungsDatum: "2018-12-11" }]
</script>

答案 3 :(得分:1)

这是我认为可以提高可读性的另一种方法:

const by = (name) => (data) => data.map(d => [d[name], d])

const topFourNewest = (...types) => types
  .reduce ( (a, b) => a.concat(b) )
  .sort ( (a, b, aa = a[0], bb = b[0]) => aa < bb ? 1 : aa > bb ? -1 : 0 )
  .map ( ([name, value]) => value )
  .slice (0, 4)

const documents = [{documentId:"ADB0125A",fileName:"test_2018.pdf",date:"2017-12-02T19:08:52+01:00"},{documentId:"123456",fileName:"test2_2018.pdf",date:"2017-12-12T22:08:52+01:00"},{documentId:"121212",fileName:"test3_2018.pdf",date:"2018-05-22T23:08:52+01:00"}]
const conversations = [{conversationId:"1102",lastUpdate:"2015-10-10T18:19:12+01:00"},{conversationId:"5622",lastUpdate:"2019-08-16T18:19:12+01:00"},{conversationId:"112",lastUpdate:"2015-10-26T18:19:12+01:00"}]
const invoices=[{invoiceId:"20100392077",rechnungsDatum:"2019-02-10"},{invoiceId:"5550392077",rechnungsDatum:"2018-02-05"},{invoiceId:"3336392077",rechnungsDatum:"2018-12-11"}]

console .log (
  topFourNewest (
    by ('date') (documents),
    by ('lastUpdate') (conversations),
    by ('rechnungsDatum') (invoices)
  )
)

我们的小辅助函数by将一个数组的每个值包装在一个由两个元素组成的数组中,键字段位于第一个,整个对象位于第二个。 (同样好的选择是将它们包装在{key, value}对象中。)

主要功能有四个步骤:reduceby中生成的这些列表合并为一个列表。 sort显然对它们进行了排序。 (对此问题,它们按降序进行排序,但是如果我要使其更通用,我可能会进行自然排序并在单独的函数中将它们取反。这仅涉及交换-1和{{1} }。)1只是提取出原始对象。然后map选择前四个元素。


我们可以想象有几种变体可以跳过helper函数,并且不会很难编写。他们可能具有以下API:

slice

topFourNewest (
  'date', documents,
  'lastUpdate', conversations,
  'rechnungsDatum', invoices
)

或者,通过辅助功能(topFourNewest ( {key: 'date', data: documents}, {key: 'lastUpdate', data: conversations}, {key: 'rechnungsDatum', data: invoices} ) ),我们可以具有更大的灵活性:

const prop = (name) => (obj) => obj[name]

甚至

topFourNewest (
  ( prop ('date'), documents ),
  ( prop ('lastUpdate'), conversations ),
  ( prop ('rechnungsDatum'), invoices )
)

但是我喜欢这个初始版本的读取方式。


我认为有几种变体很有用。我们可以参数化数字topFourNewest ( {date: documents}, {lastUpdate: conversations}, {rechnungsDatum: invoices} ) ;我们可能想要前三名或前十名是有意义的。我们可以使用第二个函数提取要选择的值的数量,从而分离出合并和排序的方式。这些将很容易做到。

答案 4 :(得分:0)

您可以编写如下内容,

const result = [
    {
        conversationId: '5622',
        lastUpdate: '2019-08-16T18:19:12+01:00'
    },
    {
        invoiceId: "20100392077",
        rechnungsDatum: "2019-02-10"
    },
    {
        invoiceId: "3336392077",
        rechnungsDatum: "2018-12-11"
    },
    {
        documentId: '121212',
        fileName: 'test3_2018.pdf',
        date: '2018-05-22T23:08:52+01:00'
    }
]

let fields = ["date","rechnungsDatum","lastUpdate"];
         
result.sort( (a,b)=> {
                let dateA, dateB;
                
                fields.forEach( field =>{
                  if(a.hasOwnProperty(field))
                    dateA = new Date(a[field]);
                    
                  if(b.hasOwnProperty(field))
                    dateB = new Date(b[field]);
                });
                
                return dateA - dateB;});
                
console.log(result.reverse());

让我知道它是否有效。

答案 5 :(得分:0)

您可以向所有数组中的每个对象添加一个sortBy字段。然后合并对象数组并根据自定义字段进行排序。获得前4个结果。然后删除sortBy列:

const documents=[{documentId:'ADB0125A',fileName:'test_2018.pdf',date:'2017-12-02T19:08:52+01:00'},{documentId:'123456',fileName:'test2_2018.pdf',date:'2017-12-12T22:08:52+01:00'},{documentId:'121212',fileName:'test3_2018.pdf',date:'2018-05-22T23:08:52+01:00'}],
    conversations=[{conversationId:'1102',lastUpdate:'2015-10-10T18:19:12+01:00'},{conversationId:'5622',lastUpdate:'2019-08-16T18:19:12+01:00'},{conversationId:'112',lastUpdate:'2015-10-26T18:19:12+01:00'}],
    invoices=[{invoiceId:"20100392077",rechnungsDatum:"2019-02-10"},{invoiceId:"5550392077",rechnungsDatum:"2018-02-05"},{invoiceId:"3336392077",rechnungsDatum:"2018-12-11"}];
    
const addSortBy = (arr, sortBy) => arr.map(a => ({ ...a, sortBy: new Date(a[sortBy]) })),
      takeCount = 4; // number of items needed in the output

// has all objects with an extra key which field to sortby
const merged = [...addSortBy(documents, "date"),
                ...addSortBy(conversations, "lastUpdate"),
                ...addSortBy(invoices, "rechnungsDatum")]

// sort based on the date property in sortBy
const output = merged.sort((a, b) => b.sortBy - a.sortBy)
                      .slice(0, takeCount)
                      .map(({ sortBy, ...rest }) => rest); // remove the sortBy field from objects
                      
console.log(output)