Как я могу отличить с условием? - PullRequest
0 голосов
/ 01 марта 2020

Вот класс UserArrived:

public class UserArrived{
   public string id{get;set;}
}

Вот класс OldUser:

public class OldUser{
   public string id{get;set;}
   public DateTime lastArrived{get;set;}
}

А вот класс User:

public class User{
   public string id{get;set;}
   public Boolean newUser{get;set;}
}

Наконец, вот два List:

List<UserArrived> UserArrivedList=new List<UserArrived>();
List<OldUser> OldUserList=new List<OldUser>();

Все идентификаторы в каждом классе уникальны.

Теперь мне нужно объединить UserArrived и OldUser для бренда new List<User>.

Как мы знаем, пользователь приходит в магазин, возможно, это новый пользователь или старый пользователь. Если идентификатор пользователя в UserArrived также содержится в OldUser, свойство newUser в новом List имеет значение false для true.

По моему мнению, я объединю два List в один первый и затем используйте метод distinct для удаления дубликатов.

Однако, кажется, distinct не может работать с условием.

Хотя я могу использовать несколько foreach для решения этой проблемы пока я чувствую, что это так хлопотно. Я хочу использовать что-нибудь простое, например lambda или linq. Как мне этого добиться?

===================================

Вот пример ввода:

List<UserArrived> UserArrivedList=new List<UserArrived>(){new UserArrived(){id="A"},new UserArrived(){id="B"},new UserArrived(){id="C"}};
List<OldUser> OldUserList=new List<OldUser>(){new OldUser(){id="B",lastArrived=DateTime.Now}};

вывод:

A,true
B,false
C,true

Ответы [ 4 ]

1 голос
/ 02 марта 2020

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

Итак, вот самый простой способ, которым я мог бы прийти чтобы сделать это:

IEnumerable<User> users =
    Enumerable
        .Concat(
            UserArrivedList.Select(i => i.id),
            OldUserList.Select(i => i.id))
        .ToLookup(x => x)
        .Select(x => new User() { id = x.Key, newUser = x.Count() == 1 });

Давайте проверим некоторые данные:

var UserArrivedList = new List<UserArrived>()
{
    new UserArrived() { id = "A" },
    new UserArrived() { id = "B" },
};

var OldUserList = new List<OldUser>()
{
    new OldUser() { id = "B" },
    new OldUser() { id = "C" },
};

Вот мои результаты:

Users

B - единственный пользователь, который появляется в обоих списках, поэтому должен быть False.


Итак, здесь есть некоторая путаница с требованиями.

ОП добавил конкретный пример входных данных и ожидаемого результата.

var UserArrivedList = new List<UserArrived>()
{
    new UserArrived() { id = "A" },
    new UserArrived() { id = "B" },
    new UserArrived() { id = "C" }
};

var OldUserList = new List<OldUser>()
{
    new OldUser() { id = "B", lastArrived = DateTime.Now }
};

С этим входом ОР ожидает True, False, True для A, B, C соответственно.

Здесь это код четырех текущих ответов:

var results = new []
{
    new
    {
        answered = "Enigmativity",
        users = Enumerable
            .Concat(
                UserArrivedList.Select(i => i.id),
                OldUserList.Select(i => i.id))
            .ToLookup(x => x)
            .Select(x => new User() { id = x.Key, newUser = x.Count() == 1 })
    },
    new
    {
        answered = "JQSOFT",
        users = UserArrivedList.Select(x => x.id)
            .Concat(OldUserList.Select(y => y.id))
            .Distinct()
            .Select(x => new User
            {
                id = x,
                newUser = OldUserList.Count(o => o.id == x) == 0,
            })
    },
    new
    {
        answered = "Anu Viswan",
        users =
            UserArrivedList
                .Join(OldUserList, ual => ual.id, oul => oul.id, (ual, oul) => new User { id = oul.id, newUser = false })
                .Concat(UserArrivedList.Select(x => x.id).Except(OldUserList.Select(x => x.id))
                .Concat(OldUserList.Select(x => x.id).Except(UserArrivedList.Select(x => x.id)))
                .Select(x=> new User{ id = x, newUser = true}))
    },
    new
    {
        answered = "Barns",
        users =
            UserArrivedList.Select(i => i.id)
                .Union(OldUserList.Select(i => i.id))
                .Select(j => new User
                {
                    id = j,
                    newUser =
                        !(UserArrivedList.Select(i => i.id).Contains(j)
                            && OldUserList.Select(i => i.id).Contains(j))})
    }
};

, который дает вывод:

All Users

Итак, в настоящее время все представленные ответы соответствуют примеру ОП.

Мне было бы интересно, чтобы ОП комментировал это как входные данные:

    var UserArrivedList = new List<UserArrived>()
    {
        new UserArrived() { id = "A" },
        new UserArrived() { id = "B" },
    };

    var OldUserList = new List<OldUser>()
    {
        new OldUser() { id = "B" },
        new OldUser() { id = "C" },
    };

Когда я запускаю это Я получаю этот вывод:

Alternative Input

Здесь три пользователя совпадают, а один нет.

Все это сводится к тому, что означает описание :

Как мы знаем, пользователь приходит в магазин, возможно, это новый пользователь или старый пользователь. Если идентификатор пользователя в UserArrived также содержится в OldUser, свойство newUser в новом списке имеет значение false для true.

1 голос
/ 02 марта 2020

Дело в LINQ - это не всегда легко. На самом деле это может стать беспорядочным. В формулировке вопроса, которую я прочитал,

Я хочу использовать что-то простое, например лямбда или linq.

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

    static void Main(string[] args)
    {

        Console.WriteLine();
        Console.WriteLine("--------------------Test This Code -----------------------");

        var combined = TestUserCombined();

        //The following is just to demonstrate the list is populated properly
        combined.OrderBy(s => s.id.PadLeft(4, '0')).ToList().ForEach(k => Console.WriteLine($"X id: {k.id} | isNew:{k.newUser}"));
    }

    private static IEnumerable<User> TestUserCombined()
    {
        List<UserArrived> userArrivedList=new List<UserArrived>();
        List<OldUser> oldUserList=new List<OldUser>();

        //populate the lists...
        for(int i = 0; i < 20; i+=2)
        {
            var userArrived = new UserArrived();
            userArrived.id = i.ToString();
            userArrivedList.Add(userArrived);
        }

        for(int i = 0; i < 20; i+=3)
        {
            var oldUser = new OldUser();
            oldUser.id = i.ToString();
            oldUserList.Add(oldUser);
        }

        //Now for the solution...
        var selectedUserArrived = userArrivedList.Select(i => i.id);
        var selectedOldUser = oldUserList.Select(i => i.id);
        var users = selectedUserArrived
                             .Union(selectedOldUser)
                             .Select(j => new User{id=j,newUser=!(selectedUserArrived.Contains(j) && selectedOldUser.Contains(j))});
        return users;
    }

Конечно, все это можно было бы сделать одним утверждением, но я считаю, что это делает его более читабельным и понятным.


РЕДАКТИРОВАТЬ: Было некоторое обсуждение среди кодеров, публикующих решения относительно того, какие именно условия должны быть выполнены, чтобы значение «newUser» было установлено в «true». Насколько я понял из первоначального опубликованного вопроса, «id» должен присутствовать в обоих списках «UserArrivedList» И «OldUserList», но я склонен согласиться с @JQSOFT, что имеет больше смысла, что единственное условие, которое должно быть выполнено, должно будь то, что «id» должен присутствовать только в «OldUserList». Если это действительно так, тогда приведенное выше выражение Select() должно быть .Select(j => new User{id=j,newUser=!selectedOldUser.Contains(j)});

0 голосов
/ 01 марта 2020

Теперь вам нужно создать отдельный список типа User из двух списков разных типов; UserArrived и OldUser объекты. Пользователь идентифицируется уникальным id строкового типа.

Соответственно, я бы предложил следующее:

var users = UserArrivedList.Select(x => x.id)
    .Concat(OldUserList.Select(y => y.id))
    .Distinct()
    .Select(x => new User
    {
        id = x,
        newUser = OldUserList.Count(o => o.id == x) == 0,
    }).ToList();

, который получает уникальные идентификаторы как из UserArrivedList, так и OldUserList и создает новый User объект для каждого. OldUserList.Count(o => o.id == x) == 0, присваивает false свойству newUser, если пользователь id существует в OldUserList, в противном случае true.

0 голосов
/ 01 марта 2020

Надеюсь, я понял ваш запрос. Один из способов добиться этого с помощью Linq:

    var users = UserArrivedList.Join(OldUserList,ual=>ual.id,oul=>oul.id,(ual,oul)=>new User{id=oul.id,newUser=false})
                               .Concat(UserArrivedList.Select(x=>x.id).Except(OldUserList.Select(x=>x.id))
                               .Concat(OldUserList.Select(x=>x.id).Except(UserArrivedList.Select(x=>x.id)))
                               .Select(x=> new User{id=x,newUser=true}));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...