javascript - лучший скрипт поиска значений во вложенных массивах - PullRequest
0 голосов
/ 31 мая 2018

Мне нужно найти значение во вложенном массиве, чтобы ответить на вопрос:

Есть ли адрес электронной почты из "type":"CONTACT" с "value":"email4@example.com"?

Iнаписал следующий основной алгоритм (см. fiddle ), который дает ожидаемый результат, но я думаю, что есть лучший и более короткий способ его решения ...

const infos = [
    {
        "resourceName":"name1",
        "id":"id1",
        "emailAddresses":[
            { "metadata":{ "primary":true,  "source":{ "type":"CONTACT", "id":"m1" } , "value":"email1@example.com"}},
            { "metadata":{ "primary":false, "source":{ "type":"CONTACT", "id":"m2" } , "value":"email2@example.com"}}
        ]
    },
    {
        "resourceName":"name2",
        "id":"id2",
        "emailAddresses":[
            { "metadata":{ "primary":true,  "source":{ "type":"FAMILY", "id":"m3" } , "value":"email3@example.com"}},
            { "metadata":{ "primary":false, "source":{ "type":"CONTACT", "id":"m4" } , "value":"email4@example.com"}},
            { "metadata":{ "primary":false, "source":{ "type":"BUSINESS", "id":"m5" } , "value":"email5@example.com"}}
        ]
    },
    {
        "resourceName":"name3",
        "id":"id3",
        "emailAddresses":[
            { "metadata":{ "primary":true,  "source":{ "type":"CONTACT", "id":"m5" } , "value":"email6@example.com"}},
            { "metadata":{ "primary":false, "source":{ "type":"FAMILY", "id":"m6" } , "value":"email7@example.com"}}
        ]
    }
];

const search_email = "email4@example.com";
let parent_key = null;

infos.forEach( info => {
    info.emailAddresses.forEach( ema => {
        if ((ema.metadata.source.type === 'CONTACT') && (ema.metadata.value === search_email )) {
            parent_key = info.id;
        }
    })
});

if ( parent_key === null) {
    console.log('NOT FOUND');
} else {
    console.log('FOUND - PARENT KEY: ', parent_key);
}

Я могу остановитьсяпоиск по первому найденному состоянию ... просто нужно знать, существует ли найденный адрес электронной почты.

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Функции some, filter и find all принимают функцию с одинаковой сигнатурой.Функция, переданная некоторым, фильтрует и находит, получает элемент массива и возвращает true или false.

Затем вы можете использовать частично примененные функции и комбинировать их, чтобы легко создавать комбинируемые фильтры, пример того, как это используетсяможно найти здесь

Если вам нужно объединить фильтры, я бы посоветовал взглянуть на код ниже, там нет комментариев, объясняющих, но вы можете найти больше информации о том, как это работает впример фильтра, упомянутый ранее.

const infos = [
  {
    "resourceName": "name1",
    "id": "id1",
    "emailAddresses": [
      { "metadata": { "primary": true, "source": { "type": "CONTACT", "id": "m1" }, "value": "email1@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "CONTACT", "id": "m2" }, "value": "email2@example.com" } }
    ]
  },
  {
    "resourceName": "name2",
    "id": "id2",
    "emailAddresses": [
      { "metadata": { "primary": true, "source": { "type": "FAMILY", "id": "m3" }, "value": "email3@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "CONTACT", "id": "m4" }, "value": "email4@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "BUSINESS", "id": "m5" }, "value": "email5@example.com" } }
    ]
  },
  {
    "resourceName": "name3",
    "id": "id3",
    "emailAddresses": [
      { "metadata": { "primary": true, "source": { "type": "CONTACT", "id": "m5" }, "value": "email6@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "FAMILY", "id": "m6" }, "value": "email7@example.com" } }
    ]
  }
];

const filterFn = getter => comparer => o =>
  comparer(getter(o))
;

const getEmailAddresses = o => (o && o.emailAddresses) || [];

const getType = o => o.metadata.source.type;

const getEmail = o => o.metadata.value;

const getPrimary = o => String(o.metadata.primary);

const isEqual = value => item => item === value;

const compareEmail = comparers => items =>
  items.some(
    item=> 
      comparers.reduce(
        (result,comparer)=>result && comparer(item),
        true
      )
  )
;
const getters = [getPrimary,getType,getEmail];
Array.from(document.querySelectorAll("select")).forEach(
  select=>{
    select.addEventListener(
      "change",
      ()=>{
        const filters = Array.from(document.querySelectorAll("select")).map(
          (select,index)=>
            (select.value==="none")
              ? x=>true
              : filterFn(getters[index])(isEqual(select.value))
        );
        console.log(
          infos.filter(filterFn(getEmailAddresses)(compareEmail(filters)))
          .map(item=>item.resourceName)
        );
      }
    )
  }
)
      <select>
        <option value="none">no filter on primary</option>
        <option value="true">primary</option>
        <option value="false">not primary</option>
      </select>
      <select>
        <option value="none">no filter on type</option>
        <option value="CONTACT">CONTACT</option>
        <option value="FAMILY">FAMILY</option>
        <option value="BUSINESS">BUSINESS</option>
      </select>
      <select>
        <option value="none">no filter on email</option>
        <option value="email1@example.com">email1@example.com</option>
        <option value="email2@example.com">email2@example.com</option>
        <option value="email3@example.com">email3@example.com</option>
        <option value="email4@example.com">email4@example.com</option>
        <option value="email5@example.com">email5@example.com</option>
        <option value="email6@example.com">email6@example.com</option>
        <option value="email7@example.com">email7@example.com</option>
      </select>
0 голосов
/ 31 мая 2018

Вы можете использовать метод Array some () в сочетании с destructuring .

Для защиты от возможного сбоя кода, когда некоторые свойства отсутствуют в объектахвашего массива infos (то есть тех, которые вы ищете), есть несколько примечательных вещей, происходящих в сущности ниже.Это:

  1. В строке кода, которая гласит:

    .some(({ emailAddresses = [] }) => emailAddresses
    

    Разрушение .Однако, возможно, что еще более важно, было указано значение по умолчанию пустого массива (то есть части = []).Это предотвратит ошибку, если один из ваших объектов в массиве infos не содержит свойства emailAddresses.Точнее говоря, это предотвратит сбой вашей программы при вызове следующего метода .some(...) (т. Е. В следующей строке кода), когда нет emailAddresses member / property.

  2. Во второй раз, когда вызывается метод .some, мы не только возвращаем логическое значение на основе оценки:

    metadata.source.type === 'CONTACT' && metadata.value === searchEmail
    

    Поскольку только выполнение этого приведет к тому, что ваша программаошибка, когда объект metadata в массиве emailAddresses не содержит элемент / свойство source.Вместо этого мы сначала оцениваем metadata.source, чтобы проверить его существование, прежде чем metadata.source.type === 'CONTACT'.Поэтому мы делаем это вместо этого:

    metadata.source && metadata.source.type === 'CONTACT' && metadata.value === searchEmail

Примечание: Комментарии 1 и 2 в приведенном ниже примере кода указывают, где свойства / значения были намеренно пропущены для демонстрациипрограмма не дает сбоя при таких обстоятельствах.

const infos = [{
    "resourceName": "name1",
    "id": "id1"
    // 1. Intentional missing `emailAddresses` property
  }, {
    "resourceName": "name2",
    "id": "id2",
    "emailAddresses": [
      { "metadata": { "primary": true, /* 2. Intentional missing `source` property */ "value": "email3@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "CONTACT", "id": "m1" }, "value": "email4@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "BUSINESS", "id": "m2" }, "value": "email5@example.com" } }
    ]
  }, {
    "resourceName": "name3",
    "id": "id3",
    "emailAddresses": [
      { "metadata": { "primary": true, "source": { "type": "CONTACT", "id": "m3" }, "value": "email6@example.com" } },
      { "metadata": { "primary": false, "source": { "type": "FAMILY", "id": "m4" }, "value": "email7@example.com" } }
    ]
  }
];

const searchEmail = "email4@example.com";

const hasFound = infos
    .some(({ emailAddresses = [] }) => emailAddresses
    .some(({ metadata }) => metadata.source
        && metadata.source.type === 'CONTACT'
        && metadata.value === searchEmail
    ));

console.log(hasFound);

Альтернативный способ защиты вашего кода:

В качестве альтернативы, Разрушение вложенных объектов с Значения по умолчанию могут быть использованы для защиты вашего кода от сбоя, когда искомые свойства не существуют в массиве infos объектов.Например:

const hasFound = infos
    .some(({ emailAddresses = [] }) => emailAddresses
    .some(({ metadata: { source = {}, value } }) =>
        source.type === 'CONTACT' && value === searchEmail
    ));

На этот раз во втором методе .some() мы деструктурируем / перейдем к вложенному объекту, чтобы получить только ту информацию, которая нам нужна, то есть source и value.Делая это, мы избегаем необходимости проверять существование metadata.source (т.е. при возврате логического значения из функции в соответствии с предыдущим описанием), потому что переменной source присваивается значение по умолчанию для пустого объекта (т.е. source = {}).

0 голосов
/ 31 мая 2018

Вы можете использовать array#some для перебора массива infos, затем снова использовать array#some для просмотра массива emailAddresses, где source type - это CONTACT, а value - адрес электронной почты, который выпредоставлена.

Метод some () проверяет, прошел ли хотя бы один элемент массива тест, реализованный предоставленной функцией.

Если элемент найден, array#some()немедленно возвращает истину.

const infos =[ { "resourceName":"name1", "id":"id1", "emailAddresses":[ { "metadata":{ "primary":true, "source":{ "type":"CONTACT", "id":"m1" } , "value":"email1@example.com"}}, { "metadata":{ "primary":false, "source":{ "type":"CONTACT", "id":"m2" }, "value":"email2@example.com"}} ] }, { "resourceName":"name2", "id":"id2", "emailAddresses":[ { "metadata":{ "primary":true, "source":{ "type":"FAMILY", "id":"m3" } , "value":"email3@example.com"}}, { "metadata":{ "primary":false, "source":{ "type":"CONTACT","id":"m4" } , "value":"email4@example.com"}}, { "metadata":{ "primary":false, "source":{ "type":"BUSINESS", "id":"m5" } , "value":"email5@example.com"}} ] }, { "resourceName":"name3", "id":"id3", "emailAddresses":[ { "metadata":{ "primary":true, "source":{"type":"CONTACT", "id":"m5" } , "value":"email6@example.com"}}, { "metadata":{ "primary":false, "source":{ "type":"FAMILY", "id":"m6" } , "value":"email7@example.com"}} ] } ],
    searchEmail = "email4@example.com";
    found = infos.some(({emailAddresses}) =>
              emailAddresses.some(({metadata}) => metadata.source.type === 'CONTACT' && metadata.value === searchEmail)
            );
console.log(found);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...