typescript 遍历对象的所有嵌套子对象,如果type等于某个字符串,则创建一个值为的平面数组

avwztpqn  于 2022-12-24  发布在  TypeScript
关注(0)|答案(3)|浏览(176)

我知道有很多问题和文章关于这一点,但我不能把我的头围绕这一点,没有什么很帮助我。

export type CarId = string;
export type CarType = 'sedan' | 'suv' | 'wagon';
export type Car = {
  id: CarId;
  type: CarType;
  options?: Record<string, string | number | boolean | string[] | null>;
  models?: Car[];
}

我有一个数据如下:(认为该对象是大得多,所以更复杂的方面嵌套和5 - 10 suv类型的汽车)

export const cars: Car = {
  type: 'sedan',
  id: 'a',
  options: {},
  models: [
    {
      type:'sedan',
      id: 'b',
      options: {},
      models: []
    },
    {
      type:'wagon',
      id: 'c',
      options: {},
      models: [
        {
          type:'wagon',
          id: 'd',
          options: {},
          models: [
              type:'suv',
              id: 'e',
              options: {
                carUrl: 'https://audi.com/a4',
                ...
              },
              models: []
          ]
        },
        {...}
      ]
    },
  ]

}

我想做的是写一个函数,如果车的类型是suv,它会给我一个carurl的平面数组。
我已经尝试了一切,我有这样的东西,现在因为我删除了很多代码,也许有一些潜力,但没有去任何地方:

export iterate = (car: Car) => {
   let urlArr = [];
   let keys = Object.keys(car);
   keys.forEach((key) => {
      if(car[key] === 'type' && (Object.values(car[key])) === 'suv') {
         urlArr.push(/*<need to push the url somehow>*/);
      }
   })
   return urlArr;
   
}

如果嵌套很深,我需要所有的URL

console.log(urlArr) should be something like ['https://audi.com/a4', 'https://bmw.com/m3', 'https://toyota.com/corolla' ...]

有人能帮我弄一下这个功能吗?
先谢谢你!

nnsrf1az

nnsrf1az1#

使用递归你可以做到这一点,这是我所做的-
1.首先,我检查了根对象的类型是否为“suv”,并且是否有任何car URL,然后推送它(您会注意到根对象的类型为“sedan”,因此它的car URL将被忽略。您可以尝试将其类型更改为“suv”)。
1.其次,我在根对象的models数组上运行一个循环,只查找“suv”类型的car URL。
1.然后,在同一个函数中,我检查了当前模型是否也有嵌套模型,然后在它们上循环并找到汽车URL。
所以,这是一个工作演示-

const carsDataObj = {
  type: "sedan",
  id: "a",
  options: {
    carUrl: "https://Seat.com/a4"
  },
  models: [
    {
      type: "suv",
      id: "b",
      options: {
        carUrl: "https://Lamborghini.com/a4"
      },
      models: []
    },
    {
      type: "suv",
      id: "b",
      options: {
        carUrl: "https://Jeep.com/a4"
      },
      models: []
    },
    {
      type: "wagon",
      id: "c",
      options: {
        carUrl: "https://F-150 Raptor.com/a4"
      },
      models: [
        {
          type: "wagon",
          id: "d",
          options: {},
          models: [
            {
              type: "suv",
              id: "e",
              options: {
                carUrl: "https://Ford.com/a4"
              },
              models: [
                {
                  type: "suv",
                  id: "e",
                  options: {
                    carUrl: "https://audi.com/a4"
                  },
                  models: []
                }
              ]
            }
          ]
        },
        {
          type: "suv",
          id: "d",
          options: {
            carUrl: "https://rolls.com/a4"
          },
          models: [
            {
              type: "suv",
              id: "e",
              options: {
                carUrl: "https://Ferrari.com/a4"
              },
              models: []
            }
          ]
        }
      ]
    }
  ]
};

let result = [];

function checkIfSUVThenPush(payload) {
  if (payload.type == "suv" && payload.options && payload.options.carUrl) {
    result.push(payload.options.carUrl);
  }
}

function loopOnModels(arr) {
  arr.forEach((item) => {
    // check if item is suv and has any car
    checkIfSUVThenPush(item);
    // Now, if item has any models then use recursion and call same method
    if (item.models && item.models.length) {
      loopOnModels(item.models);
    }
  });
  return result;
}

// First, check on root object if any car url available
checkIfSUVThenPush(carsDataObj);

// Now, loop on root object's models array
let urls = loopOnModels(carsDataObj.models);
console.log(urls);

如果成功了告诉我。

i5desfxk

i5desfxk2#

你可以使用一个递归函数来检查每辆车,然后调用models对象中的所有汽车:

function findSUVURLs(car:Car):Array<string> {
    const urlsArray:Array<string> = [];
    
    //First checking if current car is an suv and getting the url if there is one
    if (car.type === "suv" && car.options.carUrl) {
        urlsArray.push(car.options.carUrl);
    }
    
    //Then calling the same function on all cars in the 'models' property, pushing them to the same array
    car.models.forEach(subCar=>{
        //The spread operator '...' ensures we "flatten" each array and get all urls from nested objects
        urlsArray.push(...findSUVURLs(subCar));
    });
    
    return urlsArray;
}
gzjq41n4

gzjq41n43#

您可以尝试将对象展开为一个没有嵌套模型的Car对象数组,然后将其缩减为一个URL数组。

const flatten = (a: Car) => {
    if (Array.isArray(a)) return a.reduce((prev, curr) => {
      // Add the current car without models
      prev.push({...curr, models: []});
      // Check if there are nested models and flatten those too
      const nestedFlat = curr.models?.length ? flatten(curr.models) : [];
      prev.push(...nestedFlat);
      return prev;
   }, []);
   return [{...a, models: []}, ...flatten(a.models)];
}

相关问题