0
votes

Filtrer le tableau avec plusieurs propriétés tout en répondant à des termes non définis

J'ai besoin de filtrer un tableau par 4 propriétés d'objet en fonction de l'entrée de l'utilisateur, mais parfois l'utilisateur peut choisir de n'entrer que 1, 2 ou 3 termes, ce qui donne des propriétés non définies par l'utilisateur.

const myTableData = [
    {
        'date': '2020-05-16',
        'duration': 247,
        'low_temp': 373.0,
        'high_temp': 388.0,
        'type': 'XD'
    },
    {
        'date': '2020-05-27',
        'duration': 246,
        'low_temp': 373.0,
        'high_temp': 388.0,
        'type': 'LB'
    },
    {
        'date': '2020-06-04',
        'duration': 247,
        'low_temp': 374.0,
        'high_temp': 388.0,
        'type': 'LB'
    }
];

export async function filter_click(event) {
    let newArray = myTableData.filter(function (el) {
        return el.duration === Number($w("#duration").value) && el.low_temp === Number($w("#lowtemp").value) && el.high_temp === Number($w("#hightemp").value) && el.type === $w("#type").value;
    });
    $w("#table1").rows = newArray;
}

Voir si même 1 des éléments d'entrée utilisateur n'est pas rempli, cela donne un indéfini qui renvoie un tableau vide.

Pourquoi je ne peux pas utiliser || au lieu de &&

Si j'utilise le OU '||' opérateur, il ne se limite pas à TOUTES les propriétés demandées par l'utilisateur. Exemple: si 'duration' est de 350 & 'type' est 'LB' et que l'utilisateur tape dans les deux, il ne retournera pas UNIQUEMENT les objets qui ont à la fois une durée de 350 et un type de LB, à la place il renverra des objets ayant l'un ou l'autre. p>


4 commentaires

Quel comportement souhaitez-vous si le champ de données de table n'est pas défini? Il sera exclu des résultats filtrés en tant qu'entrée "non correspondante"?


Oui! Exactement. maintenant, si une propriété n'est pas définie, le tableau entier retourne simplement vide. Je voudrais que la propriété indéfinie soit exclue du filtre.


qu'est-ce que $ w dans l'exemple?


C'est l'élément d'entrée utilisateur. Similaire à document.getelementbyid


3 Réponses :


1
votes

Cela vous aidera probablement beaucoup lorsque vous essayez de résoudre un problème, pour rendre votre code plus facile à lire. À l'heure actuelle, vous avez une ligne de retour massive qui est très difficile à lire et à comprendre.

Une fonction de filtrage doit simplement renvoyer true (à tout moment) si l'élément évalué doit être inclus, et false (à tout moment) s'il doit être exclu. Ainsi, vous pouvez évaluer chacun de vos champs, un par un, pour voir s'il échoue à l'une des conditions requises et devrait être exclu , sur quoi vous renvoyez false. Sinon, à la fin de la fonction, si elle réussit tous les tests, vous savez qu'elle doit être incluse et retourner true (le "cas de base"). Ce type de filtrage inverse où vous testez les observations à exclure plutôt que les observations à inclure peut souvent être beaucoup plus facile à écrire, à lire et à raisonner.

J'écrirais également la fonction de filtre elle-même comme une fonction séparée pour le rendre plus clair, plus lisible et plus facile à entretenir.

// Exclude compared item if it fails any of the "tests"
// Otherwise include it (return true)
function filterTable(el) {
  if (el.duration !== Number($w("#duration").value) || el.duration === undefined) {
    return false;
  }
  if (el.low_temp !== Number($w("#lowtemp").value) || el.low_temp === undefined) {
    return false;
  }
  // etc. for each field to be compared

  // Base case - by this point it has passed all tests and should be included
  return true;
}

export async function filter_click(event) {
    let newArray = myTableData.filter(filterTable);
    $w("#table1").rows = newArray;
}


0 commentaires

-1
votes

Que diriez-vous d'une boucle for et d'un tableau booléen?

for (i = 0; i<array.length; i++)
     if thing != array[i]:
          bool[i] = false

for (each in bool):
    if each == false:
         do something;


1 commentaires

Il serait avantageux d'expliquer votre réponse au lieu d'un pseudo-code très limité.



0
votes

Quelques points

  1. Mettez en cache vos éléments et ne faites pas de recherches dom coûteuses dans votre Array.filter()
  2. Analysez vos paramètres afin de ne pas effectuer de transtypage inutile dans votre Array.filter()
  3. Construisez vos paramètres et transmettez-les dans le bon format à votre fonction de filtrage.
  4. Si un paramètre a été inclus - effectuez un test par rapport à l'élément de filtre actuel, sinon ignorez-le

De cette façon, vous n'effectuez pas de recherches coûteuses et ne diffusez pas à chaque itération dans le filtre. Vous n'avez pas besoin de prendre en compte les propriétés à moins que le paramètre associé n'ait été inclus.

Extrait:

<input id="duration" value="246" />
<input id="lowtemp" value="373.0" />
<input id="hightemp" value="388.0" />
<input id="type" value="LB" />
<button id="filter">filter</button>
const myTableData = [{
    'date': '2020-05-16',
    'duration': 247,
    'low_temp': 373.0,
    'high_temp': 388.0,
    'type': 'XD'
  },
  {
    'date': '2020-05-27',
    'duration': 246,
    'low_temp': 373.0,
    'high_temp': 388.0,
    'type': 'LB'
  },
  {
    'date': '2020-06-04',
    'duration': 247,
    'low_temp': 374.0,
    'high_temp': 388.0,
    'type': 'LB'
  }
];

window.addEventListener('load', () => {
  // cache the elements to avoid expensive lookups in your filter
  const $duration = document.querySelector('#duration');
  const $lowtemp = document.querySelector('#lowtemp');
  const $hightemp = document.querySelector('#hightemp');
  const $type = document.querySelector('#type');

  const filterData = (params) => {
    return myTableData.filter((item) => {
      // if we have duration, check it
      if (params.duration && item.duration !== params.duration) {
        return false;
      }

      // if we have lowtemp, check it
      if (params.low_temp && item.low_temp !== params.low_temp) {
        return false;
      }

      // if we have hightemp, check it
      if (params.high_temp && item.high_temp !== params.high_temp) {
        return false;
      }

      // if we have type, check it
      if (params.type && item.type.toLowerCase() !== params.type) {
        return false;
      }

      // include this item
      return true;
    });
  }

  document.querySelector('#filter').addEventListener('click', (e) => {
    // build up the params to filter by
    const params = {};

    if ($duration.value) {
      // parse to int 
      params.duration = parseInt($duration.value);
    }

    if ($lowtemp.value) {
      // parse to float 
      params.low_temp = parseFloat($lowtemp.value);
    }

    if ($hightemp.value) {
      // parse to float 
      params.high_temp = parseFloat($hightemp.value);
    }

    if ($type.value) {
      // convert to lowercase for comparison
      params.type = $type.value.toLowerCase();
    }

    console.info(filterData(params).length);
  });

  // few tests below
  let params = {};
  console.info(filterData(params).length === 3);

  params = {
    duration: 246
  };
  console.info(filterData(params).length === 1);

  params = {
    duration: 247
  };
  console.info(filterData(params).length === 2);

  params = {
    duration: 247,
    low_temp: 373.0
  };
  console.info(filterData(params).length === 1);

  params = {
    low_temp: 374.0,
    high_temp: 388.0
  };
  console.info(filterData(params).length === 1);

  params = {
    type: 'lb',
  };
  console.info(filterData(params).length === 2);

  params = {
    high_temp: 388.0,
  };
  console.info(filterData(params).length === 3);
});


0 commentaires