【问题标题】:JavaScript: How to map two objects to get the output which map the Id of first object to the name of other object?JavaScript:如何映射两个对象以获得将第一个对象的 ID 映射到另一个对象的名称的输出?
【发布时间】: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: ''
    },
  ]
};

【问题讨论】:

    标签: javascript arrays for-loop object


    【解决方案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, []));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      • 2013-04-13
      相关资源
      最近更新 更多