Сортировка по родителю (топологическая сортировка) и важности элемента в массиве

Если вы пришли сюда, чтобы выбрать строки из фрейма данных, включив те, чье значение столбца НЕ является ни одним из списка значений, вот как перевернуть ответ unutbu для списка значений выше:

df.loc[~df['column_name'].isin(some_values)]

(Чтобы не включать одно значение, конечно, вы просто используете обычный оператор не равно, !=.)

Пример:

import pandas as pd
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split()})
print(df)

дает нам

     A      B
0  foo    one
1  bar    one
2  foo    two
3  bar  three
4  foo    two
5  bar    two
6  foo    one
7  foo  three    

Подмножество только для тех строк, которые ARE NOT one или three в столбце B:

df.loc[~df['B'].isin(['one', 'three'])]

дает

     A    B
2  foo  two
4  foo  two
5  bar  two
2
задан Shidersz 18 January 2019 в 22:35
поделиться

2 ответа

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

Чтобы добиться замены родительской электронной почты идентификатором, просто сохраните карту родительских имен с идентификаторами:

var data = [{
  "id": 1,
  "email": "a@b.com", // unique
  "parent": "c@b.com" // is nullable
}, {
  "id": 2,
  "email": "b@b.com",
  "parent": null
}, {
  "id": 3,
  "email": "c@b.com",
  "parent": "b@b.com"
}, {
  "id": 4,
  "email": "d@b.com",
  "parent": "a@b.com"
}]

//Map email addresses to IDs
var map = data.reduce((accum, el) => {
  accum[el.email] = {
    id: el.id
  }
  return accum;
}, {});


var [root] = data.filter(el => !el.parent);
var users = [root];
var cur;
var children;
while (users.length < data.length) {
  cur = users[users.length - 1];
  //Find elments that have cur as parent
  children = data.filter(el => el.parent === cur.email);
  children.forEach(el => {
    users.push({
      id: el.id,
      email: el.email,
      parent: map[el.parent].id
    });
  });
}

console.log(users)

0
ответ дан Tom O. 18 January 2019 в 22:35
поделиться

Я подойду к этому, сначала сгенерировав новый вход с заменой parent email на parent id и новым свойством уровня узла, связанным с деревом, которому они принадлежат. Тогда мы можем отсортировать узлы по этому свойству level, а по равному level мы отсортируем по id.

const input = [
    {"id": 1, "email": "a@b.com", "parent": "c@b.com"},
    {"id": 2, "email": "b@b.com", "parent": null},
    {"id": 3, "email": "c@b.com", "parent": "b@b.com"},
    {"id": 4, "email": "d@b.com", "parent": "a@b.com"},
    {"id": 5, "email": "x@b.com", "parent": "b@b.com"},
    {"id": 6, "email": "z@b.com", "parent": "x@b.com"},
    {"id": 7, "email": "y@b.com", "parent": null},
    {"id": 8, "email": "m@b.com", "parent": "y@b.com"}
];

const findParent = (mail) => input.find(x => x.email === mail);

const getLevel = (mail, lvl) =>
{    
    return mail ? getLevel(findParent(mail).parent, lvl + 1) : lvl;
}

let newInput = input.map(({id, email, parent}) =>
{
    return {
        id: id,
        email: email,
        parent: findParent(parent) ? findParent(parent).id : null,
        lvl: getLevel(parent, 0)
    };
});

let sortedInput = newInput.sort((a, b) =>
{
    return (a.lvl - b.lvl) ? a.lvl - b.lvl : a.id - b.id;
});

console.log(sortedInput);

0
ответ дан Shidersz 18 January 2019 в 22:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: