Javascript 将数组转换为具有筛选、优先级和最小循环的对象

Javascript 将数组转换为具有筛选、优先级和最小循环的对象,javascript,arrays,algorithm,filter,reduce,Javascript,Arrays,Algorithm,Filter,Reduce,给定一个数组 const array = [{ typeName: 'welcome', orientation: 'landscape', languageId: 1, value: 'Welcome' }, { typeName: 'welcome', orientation: 'landscape', languageId: 2, value: 'Bonjour' }, { typeName: 'welcome', orientation: 'portrait', langua

给定一个数组

const array = [{
  typeName: 'welcome', orientation: 'landscape', languageId: 1, value: 'Welcome'
}, {
  typeName: 'welcome', orientation: 'landscape', languageId: 2, value: 'Bonjour'
}, {
  typeName: 'welcome', orientation: 'portrait', languageId: 2, value: 'Bonjour bonjour'
}]
我的最终目标是:

{
  welcome: {
    landscape: ['Welcome'],
    portrait: ['Bonjour bonjour']
  }
}
为此,我需要将其转换为对象,如
{typeName:{orientation:value[]}}
,如下所示:

// This is NOT what I want, it's just an intermediate form -- keep reading
{
  welcome: {
    landscape: ['Welcome', 'Bonjour'],
    portrait: ['Bonjour bonjour']
  }
}
包括优先级:如果数组中存在languageId=1,则忽略特定typeName、orientation的rest值。在上面的示例中,由于languageId=1,所以只能是['Welcome'],因此可以忽略“Bonjour”,但如果缺少languageId=1,则可以添加任何值(欢迎光临,肖像)

用对流我没有遇到任何问题..用思维方法做

但优先级排序我只能通过过滤来完成,过滤也会在内部循环。目前为止还没有问题,但若阵列非常庞大,性能就会受到影响

const数组=[{
typeName:'welcome',方向:'languageId:1,值:'welcome'
}, {
typeName:'welcome',方向:'landscape',语言ID:2,值:'Bonjour'
}, {
typeName:'welcome',方向:'Picture',语言ID:2,值:'Bonjour Bonjour'
}]
常量结果=数组
.filter((项目)=>{
return item.languageId==1||
!array.some((innerItem)=>(//我要避免的内部循环
innerItem.typeName==item.typeName&&
innerItem.orientation===item.orientation&&
innerItem.languageId==1
))
})
.减少((上一个,当前)=>({
…上一页,
[当前.类型名称]:{
…上一个[current.typeName],
[当前方向]:[
…((prev[current.typeName]|{}[current.orientation])| |[]),
当前值
]
}
}), {});

console.log(result)
您可以为prio项目设置
,并防止向数组中添加更多项目

const
数组=[{typeName:'welcome',orientation:'languageId:1,value:'welcome'},{typeName:'welcome',orientation:'languageId:2,value:'Bonjour Bonjour'},{typeName:'welcome',orientation:'Graphical',languageId:2,value:'Bonjour Bonjour'}],
hasPrio=新设置,
result=array.reduce((r,{typeName,orientation,languageId,value})=>{
var key=`${typeName}|${orientation}`;
如果(!r[typeName])r[typeName]={};
if(languageId==1){
r[typeName][orientation]=[value];
hasPrio.add(键);
}否则,如果(!hasPrio.has(键)){
如果(!r[typeName][orientation])r[typeName][orientation]=[];
r[typeName][orientation].push(值);
}
返回r;
}, {});
console.log(结果);

.as console wrapper{max height:100%!important;top:0;}
您可以使用
集合
来跟踪您是否看到了特定
类型名
语言ID===1,并且
方向
集合
是:

Set对象必须使用哈希表或其他机制实现,这些机制平均提供的访问时间与集合中的元素数呈次线性关系

因此,
集合
的性能将优于内部循环。(如果键是字符串,也可以使用对象,如下面的示例所示。如果使用,请使用
对象创建它。创建(null)
,这样它就不会继承自
对象。原型

然后只是一个简单的循环,而不是
reduce

const数组=[{
typeName:'welcome',方向:'languageId:1,值:'welcome'
},{typeName:'welcome',orientation:'landscape',languageId:1,value:'Bon dia'
}, {
typeName:'welcome',方向:'landscape',语言ID:2,值:'Bonjour'
}, {
typeName:'welcome',方向:'Picture',语言ID:2,值:'Bonjour Bonjour'
}]
const sawPriority=新集合();
const result={};
for(数组的常量{typeName,orientation,languageId,value}){
常量键=`${typeName}-${orientation}`;
常量isPriority=languageId==1;
let entry=结果[类型名称];
如果(!输入){
//还没人进来,小豌豆
entry=result[typeName]={[orientation]:[value]};
如果(优先级){
sawPriority.add(key);
}
}否则{
const hasPriority=sawPriority.has(键);
if(hasPriority==isPriority){
//新方向的第一个条目,或
//匹配优先级
常量内部=输入[方向];
如果(内部){
//随后,添加
内推(值);
}否则{
//首先是方向,创建
输入[方向]=[值];
}
}else if(优先级){
//这是一个新的优先级条目,覆盖
输入[方向]=[值];
sawPriority.add(key);
}
}
}
console.log(结果)
请参阅实时演示

const数组=[{
typeName:'welcome',方向:'languageId:1,值:'welcome'
}, {
typeName:'welcome',方向:'landscape',语言ID:2,值:'Bonjour'
}, {
typeName:'welcome',方向:'Picture',语言ID:2,值:'Bonjour Bonjour'
}];
设obj=array.reduce((acc,{orientation,value})=>{
acc[方向]=(acc[方向]| |[])。concat(值);
返回acc;
}, {});
输出={};
输出[array[0].typeName]=obj;

console.log(输出)
languageId
2,然后是1会怎样?你能假设它会被排序吗?只是一个旁注:你似乎很关心大型数组的性能。请注意,你的代码创建了很多临时对象,然后几乎立即扔掉,这会在处理大型数据时造成内存压力你不知道
array.reduce((prev, current) => ({
    ...prev,
    [current.typeName]: {
        ...prev[current.typeName],
        [current.orientation]: [
            ...(((prev[current.typeName] || {})[current.orientation]) || []),
            current.value
        ]
    }
  }), {});