JavaScript:如何映射两个对象以获得将第一个对象的 ID 映射到另一个对象的名称的输出?

Posted

技术标签:

【中文标题】JavaScript:如何映射两个对象以获得将第一个对象的 ID 映射到另一个对象的名称的输出?【英文标题】:JavaScript: How to map two objects to get the output which map the Id of first object to the name of other object? 【发布时间】:2021-08-07 03:26:06 【问题描述】:

我正在尝试制作一个将 data2 对象值映射到 data1 名称的函数。

我试图用 data1 迭代 data2 object2 但它不能正常工作。我可以映射它们,但当 data2 中不存在 data1 时,我无法获取它的值。

有什么方法可以正确映射以获得代码中提到的所需输出?

let data1 = 
    attributes: [
            Id: 'test1',
            Name: 'Test1',
            Type: 'date'
        ,
        
            Id: 'test2',
            Name: 'Test2',
            Type: 'string'
        ,
        
            Id: 'test3',
            Name: 'Test3',
            Type: 'string'
        ,
        
            Id: 'test4',
            Name: 'Test4',
            Type: 'boolean'
        
    ]
;

let data2 = 
    value: [
            test1: '10-12-2021',
            test2: '4',
            dummy: 'ignore me'
        ,
        
            test3: '3',
            test4: true,
            abc: 'ignore me'
        ,
        
            test1: '12-12-2023',
            test3: '42',
            dummy1: 'ignore me'
        
    ]
;

//output

let ouput = 
    rows: [
            Test1: '10/12/2021',
            Test2: '4',
            Test3: '',
            Test4: ''
        ,
        
            Test1: '',
            Test2: '',
            Test3: '3',
            Test4: 'Y'
        ,
        
            Test1: '12/12/2023',
            Test2: '',
            Test3: '42',
            Test4: ''
        
    ]
;

//function

function mapper(data1, data2) 
    let formattedValue = [];
    data2.value.forEach(val => 
        let data = ;
        for (let prop in val) 
            let name;
            const filter = data1.attributes.filter(el => el.Id === prop)[0];
            if (filter) 
                name = filter.Name;
                switch (filter.Type) 
                    case 'boolean':
                        data[name] =
                            val[prop] === true ? 'Y' : val[prop] === false ? 'N' : '';
                        break;
                    case 'date':
                        data[name] = new Date(val[prop]).toLocaleDateString();
                        break;
                    default:
                        data[name] = val[prop];
                        break;
                
            
        
        formattedValue.push(data);
    );

    return formattedValue;


console.log(mapper(data1, data2));

如果我将 data2 作为空值传递,我希望得到低于输出的值

let data1 = 
  attributes: [
    
      Id: 'test1',
      Name: 'Test1',
      Type: 'string'
    ,
    
      Id: 'test2',
      Name: 'Test2',
      Type: 'string'
    ,
    
      Id: 'test3',
      Name: 'Test3',
      Type: 'string'
    ,
    
      Id: 'test4',
      Name: 'Test4',
      Type: 'boolean'
    
  ]
;

let data2 = 
  value: [
  ]
;

//output

let ouput = 
  rows: [
    
      Test1: '',
      Test2: '',
      Test3: '',
      Test4: ''
    ,
  ]
;

【问题讨论】:

【参考方案1】:

const data1 = attributes:[Id:'test1',Name:'Test1',Type:'date',Id:'test2',Name:'Test2',Type:'string',Id:'test3',Name:'Test3',Type:'string',Id:'test4',Name:'Test4',Type:'boolean']
      data2 = value:[test1:'10-12-2021',test2:'4',test3:'3',test4:true,test1:'12-12-2023',test3:'42'];
      data3 = value: []

const mapper = (x, y) => 
  const row = x.attributes.map(e => [e.Id, e.Name])
        format = e =>  switch (true) 
            case typeof e === 'boolean':
              return e ? 'Y' : 'N'
            case isNaN(e) && !isNaN(Date.parse(e)):
              return new Date(e).toLocaleDateString()
            default: return e
          
  const rows = (y.value.length ? y.value : [1]).map(e => 
     Object.fromEntries(row.map(([k, v]) => [v, format(e[k]) ?? '']))
  )
  return  rows 
 

console.log(mapper(data1, data2))
console.log(mapper(data1, data3))
.as-console-wrapper  max-height: 100% !important; top: 0; 

说明:

y.value.length ? y.value : [1]

检查data.value 是否为空,如果不是则返回data.value。如果是,则返回 array 和 1 个元素(可以是任何值,只需进行 1 次迭代即可满足您对空数据的要求,因此值在这里并不重要。

其余代码应该很清楚,如果没有,请告诉我。

【讨论】:

非常感谢。如果我需要为 data1 属性添加更多类型支持怎么办?我们如何支持日期或整数等多种类型? 例如我想将当前日期格式转换为 mm/dd/yyyy @Bravo 现在是否符合您的要求?如果不是,为什么?【参考方案2】:

更新

因为即使data2.values 为空,您也需要最少的一组值。如果我们在数组为空时添加空对象,我已经给出的解决方案将起作用,因此在下面添加将解决它。

// I had to add below lines to get your desired result
// if `data2.value` is empty array
const arrayToLoop = [...data2.value];  
if(arrayToLoop.length === 0) 
  arrayToLoop.push();

现在我们将循环变量arrayToLoop 而不是data2.value

还写了一个小函数,用于根据给定类型转换值,您可以根据自己的需要扩展它

function parseValue(type, value)
    if(value.length==0)
      return '';
    
    switch(type.toLowerCase())
      case 'boolean':
        return value === true ? 'Y' : value === false ? 'N' : '';
      case 'date':
        return new Date(value).toLocaleDateString();        
      default:
        return value;
    


首先,我将获取所有键和标签映射,并查看每个键的所有值。 请注意我在下面是如何完成的。

如果您遇到任何问题,请告诉我。

function parseValue(type, value)
    if(value.length==0)
      return '';
    
    switch(type.toLowerCase())
      case 'boolean':
        return value === true ? 'Y' : value === false ? 'N' : '';
      case 'date':
        return new Date(value).toLocaleDateString();        
      default:
        return value;
    


function BusinessObjectMapper(data1, data2)
  const arrayToLoop = [...data2.value];  
  if(arrayToLoop.length === 0) 
      arrayToLoop.push();
  

  const rows = arrayToLoop.map(v=>
     let r = ;
     data1.attributes.forEach(o=>
      let Id, Name, Type = o;
      r[Name]=parseValue(Type, v[Id]||'');
     )
     return r;
  )
  
  return 
    rows
  ;


let data1 = 
  attributes: [
    
      Id: 'test1',
      Name: 'Test1',
      Type:'string'
    ,
    
      Id: 'test2',
      Name: 'Test2',
      Type:'boolean',
    ,
    
      Id: 'test3',
      Name: 'Test3',
      Type:'date'
    ,
    
      Id: 'test4',
      Name: 'Test4',
      Type:'un-known',
    
  ]
;

let data2 = 
  value: [
    
      test1: '1',
      test2: true
    ,
    
      test3: '02/02/2020',
      test4: '42'
    ,
    
      test1: 'deepak',
      test3: '01/01/2021'
    
  ]
;

let data2_empty = 
  value: []


console.log(BusinessObjectMapper(data1, data2));
console.log(BusinessObjectMapper(data1, data2_empty));

【讨论】:

谢谢,迪帕克。当 data2 有空值时失败。让 data1 = attributes: [ Id: 'test1', Name: 'Test1' , Id: 'test2', Name: 'Test2' , Id: 'test3' ,名称:'Test3' , ID:'test4',名称:'Test4'] ;让 data2 = 值:[ ] ; //输出 let 输出 = rows: [ Test1: '', Test2: '', Test3: '', Test4: '' , ] ; 我还修改了问题以支持类型 实际上你的 data2 不正确它不是正确的对象它应该是 value: [ ] ; 注意value 是一个可以清空对象的array 所以 而不是单个 希望它现在清楚? 我的错。 data2 将是 value:[ ] 我稍微修改了问题以支持不同的类型。是否可以更新解决方案? 不要让它变得敏捷请:P,当有完整代码时,您至少可以应用 switch case,打开 50 的赏金看起来像您正在参加我们的考试并想要准确的结果,那么只会给 50 分.社区是为了帮助你解决你的问题。没有完全完成你的任务。【参考方案3】:

我通过使用扩展运算符和 Array.prototype.reduce() 解决了对象类型问题。

const data1 = 
      attributes: [
        
          Id: "test1",
          Name: "Test1",
          Type: "date",
        ,
        
          Id: "test2",
          Name: "Test2",
          Type: "string",
        ,
        
          Id: "test3",
          Name: "Test3",
          Type: "string",
        ,
        
          Id: "test4",
          Name: "Test4",
          Type: "boolean",
        ,
      ],
    ;

    const data2 = 
      value: [
        
          test1: "10-12-2021",
          test2: "4",
        ,
        
          test3: "3",
          test4: true,
        ,
        
          test1: "12-12-2023",
          test3: "42",
        ,
      ],
    ;

    //function

    const data11 = 
      attributes: [
        
          Id: "test1",
          Name: "Test1",
          Type: "string",
        ,
        
          Id: "test2",
          Name: "Test2",
          Type: "string",
        ,
        
          Id: "test3",
          Name: "Test3",
          Type: "string",
        ,
        
          Id: "test4",
          Name: "Test4",
          Type: "boolean",
        ,
      ],
    ;

    const data12 = 
      value: [],
    ;

    function mapper(data1, data2) 
      const columns = data1.attributes.reduce((prev, item) => 
        prev[item["Id"]] = item;
        return prev;
      , );
      const emptyValues = Object.keys(columns).reduce((prev, item) => 
        prev[columns[item].Name] = "";
        return prev;
      , );
      const getValueByType = (key, v) => 
        switch (columns[key].Type) 
          case "boolean":
            return v ? "Y" : "N";
          case "date":
            return new Date(v).toLocaleDateString();
          default:
            return v;
        
      ;

      return 
        rows:
          (data2.value &&
            (data2.value.length == 0
              ? [emptyValues]
              : data2.value.map((row) =>
                  Object.entries(row).reduce(
                    (rlt, [key, v]) => 
                      rlt[columns[key].Name] = getValueByType(key, v);
                      return rlt;
                    ,
                     ...emptyValues 
                  )
                ))) ||
          [],
      ;
    

    const result1 = mapper(data1, data2);
    console.log(result1.rows);
    const result2 = mapper(data11, data12);
    console.log(result2);

【讨论】:

它没有检查类型(布尔值,日期) 为什么需要验证?我们使用原始数据值而不是空字符串 '' 如果您在预期输出中看到我正在更改日期和布尔数据 输出中出现的是“Id”而不是“Name”,例如,根据输出,它应该是“Test1”而不是 test1 @Bravo 我使用名称而不是 id【参考方案4】:

@ulou 的回答很棒!可以使用 reduce 来完成。我稍微更新了一个来源。

const mapper = (arr1, arr2) => 
    const keys = arr1.attributes.map(item => ( Id: item.Id, Name: item.Name ));
    const format = e => 
        switch (true) 
            case typeof e === 'boolean': return e ? 'Y' : 'N'
            case isNaN(e) && !isNaN(Date.parse(e)):
                return new Date(e).toLocaleDateString()
            default: return e
        
    

    const mapped = (arr2.value ?? [0]).map(item => keys.reduce((prev, cur) => (
         ...prev, [cur.Name]: format(item[cur.Id] ?? '') 
    ), ));

    return  rows: mapped ;


console.log(mapper(data1, data2));
console.log(mapper(data1, []));

【讨论】:

以上是关于JavaScript:如何映射两个对象以获得将第一个对象的 ID 映射到另一个对象的名称的输出?的主要内容,如果未能解决你的问题,请参考以下文章

Python Pandas:排序和分组,然后将第二列的两个连续行求和以获得第三列的特定值

如何在JavaScript中通过加工一些值来更新第一对象和第二对象。

如何将第三个按钮添加到 Android 警报对话框?

如何映射 javascript 数组的 i 和 i+1 值?

如何从两个现有对象正确创建对象

如何获得两个日期对象之间的小时差? [复制]