Б>По-момему код выбирает один элемент из списка, а надо было объединить несколько элементов в один
Код 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 вместе.
Тогда как ТС, ставит перед алгоритмом две задачи:
предположение, что все объекты из списка относятся к одному человеку.
<...>
позволяющий это проверить
схлопнуть" список в один максимально заполненный объект (как последний в списке),