Search code examples
javascriptarraysmultidimensional-arraypivot-tabletranspose

transform/pivot array of objects based on values of a key and reconvert it back to original


I want be able to convert below array or objects with uniform keys, but have it pivoted or transformed into array of objects, but with as many objects as there are properties in an object, with each object now having the name of property along with keys for each value for a specified key in the original (in this case all the possible vales of they "year" from original array). And I also want to get this array re-transposed into original form.

I want to know if this is possible to do in a generic way so it can be done with any type of object and based on any of its key's values.

Input:

[
    {
        "property0": "property0_2024",
        "property1": "property1_2024",
        "property2": "property2_2024",
        "property3": "property3_2024",
        "property4": "property4_2024",
        "year": "2024"
    },
    {
        "property0": "property0_2025",
        "property1": "property1_2025",
        "property2": "property2_2025",
        "property3": "property3_2025",
        "property4": "property4_2025",
        "year": "2025"
    },
    {
        "property0": "property0_2026",
        "property1": "property1_2026",
        "property2": "property2_2026",
        "property3": "property3_2026",
        "property4": "property4_2026",
        "year": "2026"
    },
    {
        "property0": "property0_2027",
        "property1": "property1_2027",
        "property2": "property2_2027",
        "property3": "property3_2027",
        "property4": "property4_2027",
        "year": "2027"
    }
]

Output:

[
    {
        "propertyName": "property0",
        "year_2024": "property0_2024",
        "year_2025": "property0_2025",
        "year_2026": "property0_2026",
        "year_2027": "property0_2027"
    },
    {
        "propertyName": "property1",
        "year_2024": "property1_2024",
        "year_2025": "property1_2025",
        "year_2026": "property1_2026",
        "year_2027": "property1_2027"
    },
    {
        "propertyName": "property2",
        "year_2024": "property2_2024",
        "year_2025": "property2_2025",
        "year_2026": "property2_2026",
        "year_2027": "property2_2027"
    },
    {
        "propertyName": "property3",
        "year_2024": "property3_2024",
        "year_2025": "property3_2025",
        "year_2026": "property3_2026",
        "year_2027": "property3_2027"
    },
    {
        "propertyName": "property4",
        "year_2024": "property4_2024",
        "year_2025": "property4_2025",
        "year_2026": "property4_2026",
        "year_2027": "property4_2027"
    }
]

Solution

  • You can pivot your data around a specified key.

    Use a Set to uniquely store your properties, filtering out duplicates.

    Then, it’s just a matter of generating a new array in which each entry is a new object with values taken from the input array.

    Here’s an example:

    function pivotData(inputArray, pivotKey, propertyKeyName = "propertyName") {
      // Consider only unique properties and exclude the pivotKey
      const properties = new Set();
      const pivotValues = [];
    
      inputArray.forEach((item) => {
        Object.keys(item).forEach((key) => {
          if (key !== pivotKey) {
            properties.add(key);
          }
        });
        pivotValues.push(item[pivotKey]);
      });
    
      const result = [];
      properties.forEach((property) => {
        const obj = {};
        obj[propertyKeyName] = property;
        inputArray.forEach((item) => {
          const pivotValue = item[pivotKey];
          const key = `${pivotKey}_${pivotValue}`;
          obj[key] = item[property];
        });
        result.push(obj);
      });
    
      return result;
    }
    
    function reversePivotData(
      pivotedArray,
      pivotKey,
      propertyKeyName = "propertyName"
    ) {
      const result = [];
      const pivotValuesSet = new Set();
    
      // Collect all pivot values from the keys in the pivoted array
      pivotedArray.forEach((item) => {
        Object.keys(item).forEach((key) => {
          if (key !== propertyKeyName) {
            const [keyPrefix, ...pivotValueParts] = key.split("_");
            if (keyPrefix === pivotKey) {
              const pivotValue = pivotValueParts.join("_");
              pivotValuesSet.add(pivotValue);
            }
          }
        });
      });
    
      const pivotValues = Array.from(pivotValuesSet);
    
      // Initialize an object for each pivot value
      pivotValues.forEach((pivotValue) => {
        const obj = {};
        obj[pivotKey] = pivotValue;
    
        pivotedArray.forEach((item) => {
          const propertyName = item[propertyKeyName];
          const key = `${pivotKey}_${pivotValue}`;
          if (item.hasOwnProperty(key)) {
            obj[propertyName] = item[key];
          }
        });
    
        result.push(obj);
      });
    
      return result;
    }
    
    // Example usage:
    const inputData = [
      {
        property0: "property0_2024",
        property1: "property1_2024",
        property2: "property2_2024",
        property3: "property3_2024",
        property4: "property4_2024",
        year: "2024",
      },
      {
        property0: "property0_2025",
        property1: "property1_2025",
        property2: "property2_2025",
        property3: "property3_2025",
        property4: "property4_2025",
        year: "2025",
      },
      {
        property0: "property0_2026",
        property1: "property1_2026",
        property2: "property2_2026",
        property3: "property3_2026",
        property4: "property4_2026",
        year: "2026",
      },
      {
        property0: "property0_2027",
        property1: "property1_2027",
        property2: "property2_2027",
        property3: "property3_2027",
        property4: "property4_2027",
        year: "2027",
      },
    ];
    
    const pivotedData = pivotData(inputData, "year");
    console.log("Pivoted Data:", pivotedData);
    
    const reversedData = reversePivotData(pivotedData, "year");
    console.log("Reversed Data:", reversedData);