通过设计不良的API进行迭代,其中对象键由文本和数字组成 [英] Iterating through a badly designed API where object keys consist of text and numbers

查看:53
本文介绍了通过设计不良的API进行迭代,其中对象键由文本和数字组成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前正在使用用于搜索饮料配方的网络应用程序.这个想法是搜索一种饮料,并向用户显示名称,成分和测量值.我正在努力寻找一种有效的方法来遍历API响应,因为它们不会作为数组返回.以下是示例响应.

Currently working on a web app used to search for drink recipes. The idea is to search for a drink and have the name, ingredients and measurements displayed to the user. I am struggling to find an efficient way to iterate through the API response as they do not come back as an array. Below is an example response.

dateModified :"2015-08-18 14:54:32"   
idDrink:"11668"    
strAlcoholic:"Alcoholic
strCategory:"Ordinary Drink"
strDrink: "Long Island Tea"
strDrinkThumb:  "https://www.thecocktaildb.com/images/media/drink/ywxwqs1439906072.jpg"
strGlass: "Highball glass"
strIBA:null
strIngredient1: "Vodka"
strIngredient2:"Light rum"
strIngredient3:"Gin" 
strIngredient4:"Tequila"  
strIngredient5: "Lemon"
strIngredient6: "Coca-Cola" 
strIngredient7:""
strIngredient8:""
strIngredient9:""
strIngredient10:""
strIngredient11:""
strIngredient12:""
strIngredient13:""
strIngredient14:""
strIngredient15:""
strInstructions: 
"Combine all ingredients (except cola) and pour over ice in a highball glass. Add the splash of cola for color. Decorate with a slice of lemon and serve." 
strMeasure1:"1/2 oz "
strMeasure2:"1/2 oz "
strMeasure3: "1/2 oz "
strMeasure4: "1/2 oz "
strMeasure5:"Juice of 1/2 "
strMeasure6:"1 splash "
strMeasure7:" "
strMeasure8:" "
strMeasure9:" "
strMeasure10:" "
strMeasure11:" "
strMeasure12:" "
strMeasure13:" "
strMeasure14:" "
strMeasure15:" "
strVideo: null

目标是将某些信息映射到表中.有没有一种迭代的方法来清理此问题,以便仅返回具有值的成分?还是创建单独的文件来格式化配料的最佳解决方案?

The goal is to map some of the information to a table. Is there an iterative way to clean this up so that only ingredients with values are returned? Or is the best solution to create a separate file for formatting the ingredients?

目前,我能想到的阻力最小的路径是创建以下15次:strIngredient1 !="".

Currently, the path of least resistance I can think of is creating the following 15 times: strIngredient1 !="".

下面是API调用:

$('#drinkSearch').click(function(){
  var word = document.getElementById("sbar").value;

  event.preventDefault();
  console.log(word)
  $.getJSON("https://www.thecocktaildb.com/api/json/v1/1/search.php?s="+ word, function(Result) {
    console.log(Result)
    Result.drinks.forEach(function(ingredients){
       var ing1 = ingredients.strIngredient1;

       console.log(ing1);
    })
  });
});

推荐答案

API为每种饮料使用strIngredient1strIngredient15strMeasure1strMeasure15等键返回每种饮料的对象.

The API returns an object for each drink with keys like strIngredient1 through strIngredient15, strMeasure1 through strMeasure15, etc. — indeed badly designed.

您可以将所有这些收集在一个数组中.有两种处理空值的方法.您可以仅过滤空值使度量值与其成分匹配:

You can gather all these in an array. There are two different approaches of handling empty values. You can either simply filter empty values or match measures to their ingredients:

这些方法只是从每个要构建的数组中删除空值.这可能导致不一致,因为strMeasure键实际上取决于strIngredient键,在位置上.查找下面的匹配方法以解决此问题.

These approaches just remove empty values from each to-be-built array. This can lead to inconsistencies since the strMeasure keys actually depend on the strIngredient keys, positionally. Look for the matching approach below to fix that.

另一个问题是,成分和措施有时可能会乱序. 匹配方法不存在此问题.

Another issue is that the ingredients and measures may be out-of-order sometimes. The matching approach doesn’t have this issue.

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    ingredientsArray = drinkEntries
      .filter(([key, value]) => key.startsWith("strIngredient") && value && value.trim())
      .map(([key, value]) => value),
    measuresArray = drinkEntries
      .filter(([key, value]) => key.startsWith("strMeasure") && value && value.trim())
      .map(([key, value]) => value);

  console.log("Ingredients:", ingredientsArray);
  console.log("Measures:", measuresArray);
});

filter key.startsWith("strIngredient")确保获得正确的十五个键,而&& value && value.trim()确保该值既不是null也不是空,也不只是空格(因此

In the filter, key.startsWith("strIngredient") ensures that you get the right fifteen keys, and && value && value.trim() ensures that the value is neither null, nor empty, nor just whitespace (hence trim). All three variations are used randomly.

一个不太多余的表格可能看起来像这样:

A less redundant form could look like this:

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    [
      ingredientsArray,
      measuresArray
    ] = [
      "strIngredient",
      "strMeasure"
    ].map((keyName) => drinkEntries
      .filter(([key, value]) => key.startsWith(keyName) && value && value.trim())
      .map(([key, value]) => value));

  console.log("Ingredients:", ingredientsArray);
  console.log("Measures:", measuresArray);
});

匹配其成分的措施

此方法首先为strIngredientstrMeasure建立两个数组.用parseInt(key.slice(keyName.length))提取数字键. Object.assign 将几个{key: value}对象放置到一个数组上,其中key是数字,表示使用这些数字键和这些值构建一个数组. 1

Match measures to their ingredients

This approach first builds two arrays for strIngredients and strMeasures. The numeric keys are extracted with parseInt(key.slice(keyName.length)). Object.assigning several {key: value} objects onto an array, where keys are numeric, means building an array with those numeric keys and those values.1

然后对值进行过滤,以使如果具有相同索引任何值非空,则这些值将保留.

Then the values are filtered such that they remain if any value with the same index is non-empty.

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    // This part build arrays out of the two sets of keys
    [
      ingredientsArray,
      measuresArray
    ] = [
      "strIngredient",
      "strMeasure"
    ].map((keyName) => Object.assign([], ...drinkEntries
        .filter(([key, value]) => key.startsWith(keyName))
        .map(([key, value]) => ({[parseInt(key.slice(keyName.length))]: value})))),

    // This part filters empty values based on the ingredients
    {
      finalIngredients,
      finalMeasures
    } = ingredientsArray.reduce((results, value, index) => {
      if(value && value.trim() || measuresArray[index] && measuresArray[index].trim()){
        results.finalIngredients.push(value);
        results.finalMeasures.push(measuresArray[index]);
      }

      return results;
    }, {
      finalIngredients: [],
      finalMeasures: []
    }),

    // Optional: zip both arrays
    ingredientsWithMeasures = finalIngredients
      .map((value, index) => [finalMeasures[index], value]);

  // Output
  console.log("Ingredients:", finalIngredients);
  console.log("Measures:", finalMeasures);

  console.log("All ingredients and measures:\n", ingredientsWithMeasures
    .map(([measure, ingredient]) => `${(measure || "").trim()} ${(ingredient || "").trim()}`)
    .join("\n"));
});


1 :通常使用


1: Building an array from objects often also works with Array.from, but it requires a length property as well. Instead of calculating that, I just went ahead and used Object.assign instead.

这篇关于通过设计不良的API进行迭代,其中对象键由文本和数字组成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆