Как "схлопнуть" список?
От: mDmitriy Россия  
Дата: 03.05.24 10:16
Оценка:
Всем привет!
public class Person
{
    public string SurName;
    public string FirstName;
    public string Patronymic;
}
...
var inputList = new List<Person>()
{
    new() { SurName = "Иванов", FirstName = "", Patronymic = "", },
    new() { SurName = "", FirstName = "Иван", Patronymic = "", },
    new() { SurName = "Иванов", FirstName = "Иван", Patronymic = "", },
    new() { SurName = "", FirstName = "Иван", Patronymic = "Иванович", },
    new() { SurName = "Иванов", FirstName = "Иван", Patronymic = "Иванович", },
};

Есть более чем вероятное предположение, что все объекты из списка относятся к одному человеку.
Имеется ли более-менее вменяемый алгоритм, позволяющий это проверить и "схлопнуть" список в один максимально заполненный объект (как последний в списке), который и вернуть?
По принципу "пустое поле == заполненному или имеющему такое же значение"

Спасибо

PS. Количество элементов в списке может быть произвольным
Re: Как "схлопнуть" список?
От: Буравчик Россия  
Дата: 03.05.24 11:06
Оценка: 6 (1)
Здравствуйте, mDmitriy, Вы писали:

D>Имеется ли более-менее вменяемый алгоритм, позволяющий это проверить и "схлопнуть" список в один максимально заполненный объект (как последний в списке), который и вернуть?

D>По принципу "пустое поле == заполненному или имеющему такое же значение"

В такой постановне не сложно, O(N). Пробегашь по списку, когда встречаешь значение поля, записываешь его в результат (в заполненный объект).
Если встретил значение, отличное от того, которое уже лежит в результате, то возвращаешь ошибку.
Best regards, Буравчик
Re: Как "схлопнуть" список?
От: Pavel Dvorkin Россия  
Дата: 03.05.24 11:10
Оценка: 6 (1) +1
Здравствуйте, mDmitriy, Вы писали:

D>Всем привет!

D>
D>public class Person
D>{
D>    public string SurName;
D>    public string FirstName;
D>    public string Patronymic;
D>}
D>...
D>var inputList = new List<Person>()
D>{
D>    new() { SurName = "Иванов", FirstName = "", Patronymic = "", },
D>    new() { SurName = "", FirstName = "Иван", Patronymic = "", },
D>    new() { SurName = "Иванов", FirstName = "Иван", Patronymic = "", },
D>    new() { SurName = "", FirstName = "Иван", Patronymic = "Иванович", },
D>    new() { SurName = "Иванов", FirstName = "Иван", Patronymic = "Иванович", },
D>};
D>

D>Есть более чем вероятное предположение, что все объекты из списка относятся к одному человеку.
D>Имеется ли более-менее вменяемый алгоритм, позволяющий это проверить и "схлопнуть" список в один максимально заполненный объект (как последний в списке), который и вернуть?
D>По принципу "пустое поле == заполненному или имеющему такое же значение"

D>Спасибо


D>PS. Количество элементов в списке может быть произвольным


Просто завести 3 переменные SurName,FirstName и Patronymic с начальными значениями "" и в цикле сравнивать с полями. Если переменная пуста, присваивать ей значение поля. Если не пуста — сравнивать ее с полем, при неравенстве — предположение неверно, при равенстве — ничего не делать.

После цикла создать новую Person с этими значениями, а список выкинуть.
With best regards
Pavel Dvorkin
Re: Как "схлопнуть" список?
От: sergii.p  
Дата: 03.05.24 11:38
Оценка: 6 (1)
Здравствуйте, mDmitriy, Вы писали:

inputList.GroupBy(o => o, ObjectsAreSimilar).Select(ChooseMaxFull);


O(NlogN) зато максимально понятно
Re[2]: Как "схлопнуть" список?
От: mDmitriy Россия  
Дата: 03.05.24 11:51
Оценка:
Здравствуйте, sergii.p, Вы писали:
SP>
SP>inputList.GroupBy(o => o, ObjectsAreSimilar).Select(ChooseMaxFull);
SP>


SP>O(NlogN) зато максимально понятно


мне непонятно, можете раскрыть?
ObjectsAreSimilar и ChooseMaxFull, видимо, методы, которые и должны делать то что я спрашиваю
Re[3]: Как "схлопнуть" список?
От: sergii.p  
Дата: 03.05.24 12:33
Оценка: 6 (1)
Здравствуйте, mDmitriy, Вы писали:

D>мне непонятно, можете раскрыть?


что-то подобное
bool StringsAreSimilar(string s1, string s2) {
    if(s1 == null || s2 == null) return true;
    return s1 == s2;
}

bool ObjectsAreSimilar(Person p1, Person p2) {
    return StringsAreSimilar(p1.SurName, p2.SurName)
        && StringsAreSimilar(p1.FirstName, p2.FirstName)
        && StringsAreSimilar(p1.SecondName, p2.SecondName)
}

int MoreFull(string s1, string s2) {
    return s1 == null ? (s2 == null ? 0 : -1) : 1;
}

int MoreFull(Person p1, Person p2) {
    var f1 = MoreFull(p1.SurName, p2.SurName);
    if f1 != 0 return f1;
    var f2 = MoreFull(p1.FirstName, p2.FirstName);
    if f2 != 0 return f1;
    var f3 = MoreFull(p1.SecondName, p2.SecondName);
    if f3 != 0 return f1;
}

Person ChooseMaxFull(IEnumerable<Person> list) => list.MaxBy(p => p, MoreFull);
Re[4]: Как "схлопнуть" список?
От: m2user  
Дата: 03.05.24 14:57
Оценка: 6 (1)
SP>что-то подобное

Ваш ObjectsAreSimilar не транзитивен.

Person p1 = new() { SurName = "A", FirstName = "", Patronymic = "", }
Person p2 = new() { SurName = "", FirstName = "B", Patronymic = "", }
Person p3 = new() { SurName = "C", FirstName = "", Patronymic = "", }


p1 равно p2 и p2 равно p3, но p1 не равно p2 (при сравнении через ObjectsAreSimilar).
Re[4]: Как "схлопнуть" список?
От: Буравчик Россия  
Дата: 03.05.24 15:06
Оценка: 6 (1)
Здравствуйте, sergii.p, Вы писали:

SP>что-то подобное

SP>
SP>Person ChooseMaxFull(IEnumerable<Person> list) => list.MaxBy(p => p, MoreFull);
SP>


По-момему код выбирает один элемент из списка, а надо было объединить несколько элементов в один

Проще написать "объединялку" значений (сорри за питон в .NET-разделе)

def combineValues(values: List[str]) -> str:
    validValues = (v for v in values if v != "")
    return next(validValues, "")

def combinePersons(persons: List[Person]) -> Person:
    return Person(
        SurName = combineValues(p.SurName for p in persons),
        FirstName = combineValues(p.FirstName for p in persons),
        Patronymic = combineValues(p.Patronymic for p in persons),
    )


  Полный работающий код
from typing import List
from dataclasses import dataclass

@dataclass
class Person:
    SurName: str
    FirstName: str
    Patronymic: str
    
def combineValues(values: List[str]) -> str:
    validValues = (v for v in values if v != "")
    return next(validValues, "")

def combinePersons(persons: List[Person]) -> Person:
    return Person(
        SurName = combineValues(p.SurName for p in persons),
        FirstName = combineValues(p.FirstName for p in persons),
        Patronymic = combineValues(p.Patronymic for p in persons),
    )

print(
    combinePersons([
        Person("", "", "pat"),
        Person("sur", "", "pat"),
        Person("", "fir", "pat"),
    ])
)
Best regards, Буравчик
Re[5]: Как "схлопнуть" список?
От: m2user  
Дата: 03.05.24 18:38
Оценка: 6 (1)
Б>По-момему код выбирает один элемент из списка, а надо было объединить несколько элементов в один

Код sergii.p группирует объекты по признаку озвученному ТС ("пустое поле == заполненному или имеющему такое же значение") и выбирает самый заполненный объект из группы.
И он расчитан на нескольких реальных персон в списке, т.е. результат это список, в отличие от Вашего алгоритма.

Но работать будет не вполне корректно, хотя бы на том примере что я уже приводил:

Person p1 = new() { SurName = "A", FirstName = "", Patronymic = "", }
Person p2 = new() { SurName = "", FirstName = "B", Patronymic = "", }
Person p3 = new() { SurName = "C", FirstName = "", Patronymic = "", }


Надо придумать более хитрый алгоритм: например придать разный вес полям при группировке.

Б>Проще написать "объединялку" значений (сорри за питон в .NET-разделе)


Помоему Ваш код рассчитан на то, что в списке только одна реальная персона, и надо просто скомбинировать значения из разных объектов Person вместе.
Тогда как ТС, ставит перед алгоритмом две задачи:

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

схлопнуть" список в один максимально заполненный объект (как последний в списке),

Re[6]: Как "схлопнуть" список?
От: mDmitriy Россия  
Дата: 21.05.24 08:35
Оценка:
Здравствуйте, m2user, Вы писали:
M>
M>Person p1 = new() { SurName = "A", FirstName = "", Patronymic = "", }
M>Person p2 = new() { SurName = "", FirstName = "B", Patronymic = "", }
M>Person p3 = new() { SurName = "C", FirstName = "", Patronymic = "", }
M>


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