减少对象数组并使用回退值

3

考虑以下对象:

var content = [
    {
        id: 'tab1',
        langCode: 'en',
        title: 'rocket'
    },
    {
        id: 'tab1',
        langCode: 'da',
        title: 'raket'
    },
    {
        id: 'tab2',
        langCode: 'en',
        title: 'factory'        
    },
    {
        id: 'tab3',
        langCode: 'es',
        title: 'boligrafo'
    },      
];

我希望将此数组简化为一个新数组,并遵循以下限制:
  • 不含重复ID
  • 首选本地语言的值
  • 如果没有本地翻译,请回退到英文
  • 丢弃所有其他翻译(即使它们具有唯一的ID)
这意味着,如果本地语言是丹麦语,则从上面的数据输出将如下所示:
[
    {
        id: 'tab1',
        langCode: 'da',
        title: 'raket'
    },
    {
        id: 'tab2',
        langCode: 'en',
        title: 'factory'        
    },
];

我的目标是尽可能让代码短小易读,我可以充分利用ES6和Lodash。以下是我的代码:

const LOCAL_LANG = 'da'; // Hard coded for the sake of the example

let localArr = content.filter(item => item.langCode === LOCAL_LANG);

if(LOCAL_LANG !== 'en') {
    let enArr = content.filter(item => item.langCode === 'en');
    for (let i = 0; i < enArr.length; i++) {
        if (!_.find(localArr, { 'id': enArr[i].id})) {
            localArr.push(enArr[i]);
        }
    }
}

这样做虽然能达到效果,但会创建两个重复的数组,然后以我认为有些笨拙的方式将它们合并在一起。我希望看到更优雅的解决方案,最好是不必多次传递数组的方法。
另一个(可能稍微更清晰)的解决方案是在第一次通过时在langCode ==='da'|| langCode ==='en'上减小数组,然后删除重复项……但我仍然觉得我错过了最明显的解决方案。
谢谢!

本地语言的值应该优先考虑,你怎么知道呢? - Nina Scholz
我假设英语是备选语言,但对于其他语言,我们如何知道哪种是本地语言。 - Redu
@NinaScholz 我已经把本地语言存储在一个变量中了。我会将它添加到我的示例中。 - Nix
也许您可以添加更多的数据以更好地反映您的需求。 - Nina Scholz
3个回答

2

我会将所有内容缩减成一个以ID为键的对象,以便于进行简单查找,无需使用额外的_.find调用:

const targetLang = 'da';
const fallbackLang = 'en';

const itemsByKey = content.reduce((allItems, item) => {
  if (item.langCode === targetLang 
      || (!(item.id in allItems) && item.langCode === fallbackLang)) 
  {
    return Object.assign(allItems, { [item.id]: item });
  } else {
    return allItems;
  }
}, {});

这个解决方案只需要对原始数组进行一次遍历。如果您需要将此查找对象转换回数组,则需要进行第二次遍历。
var normalizedArray = Object.keys(itemsByKey).map(key => itemsByKey[key]);

1
你可以使用树形结构并过滤所需的项。

var content = [{ id: 'tab1', langCode: 'en', title: 'rocket' }, { id: 'tab1', langCode: 'da', title: 'raket' }, { id: 'tab2', langCode: 'es', title: 'boligrafo' }, { id: 'tab2', langCode: 'en', title: 'pen' }],
    object = Object.create(null);

content.forEach(function (a) {
    object[a.id] = object[a.id] || {}
    object[a.id][a.langCode] = a;
});  

var result = Object.keys(object).map(k => object[k][Object.keys(object[k]).filter(l => l !== 'en')[0] || 'en']);

console.log(result);


1
我会按照以下方式进行。

var content = [
    {
        id: 'tab1',
        langCode: 'en',
        title: 'rocket'
    },
    {
        id: 'tab1',
        langCode: 'da',
        title: 'raket'
    },
    {
        id: 'tab2',
        langCode: 'es',
        title: 'boligrafo'
    },
    {
        id: 'tab2',
        langCode: 'en',
        title: 'pen'
    }
],
result = content.sort((a,b) => a.langCode === "en" ? 1 : -1)
                .reduce((p,c) => p.findIndex(o => o.id === c.id) === -1  ? p.concat(c) : p,[]);
console.log(result);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接