Лучшая практика, чтобы найти наиболее подходящий экземпляр в списке C # - PullRequest
0 голосов
/ 13 ноября 2018

Конечно, очень простой вопрос для большинства из вас.Но сейчас я борюсь с решением.

Представьте, что у вас есть список кошек (List), где у каждой кошки есть список младенцев (котенок)

public class Cat
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Race { get; set; }
        public bool Gender { get; set; }
        public List<Kitten> Babys { get; set; }  
    }

public class Kitten
    {
        public string Name { get; set; }
        public double Age { get; set; }
        public bool Gender { get; set; }
    }

Теперь я хочунайти кота, у которого больше всего совпадений для заданных требований.Может легко случиться так, что кошка соответствует только 2 из 3 требований.Я просто хочу найти кошку, которая наиболее соответствует моим требованиям.

, где мои требования могут быть:

  • Имя должно быть "Micky"
  • Возраст 42
  • Имеет котенка по имени "Мини"

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

Заранее спасибо

Ответы [ 4 ]

0 голосов
/ 13 ноября 2018

Несмотря на то, что это наиболее общее решение, которое есть (нужны некоторые улучшения в крайнем случае):

  public class ReflectCmpare
    {
        public PropertyInfo PropertyInfo { get; set; }
        public dynamic Value { get; set; }
    }


    public Cat GetBestCat(List<Cat> listOfCats, List<ReflectCmpare> catParamsToCompare, List<ReflectCmpare> kittensParamsToCompare)
    {
        var bestScore = 0;
        var ret = listOfCats[0];
        foreach (var cat in listOfCats)
        {
            var score = catParamsToCompare.Sum(param => param.PropertyInfo.GetValue(cat, null) == param.Value ? 1 : 0);
            foreach (var baby in cat.Babys)
            {
                score+= kittensParamsToCompare.Sum(param => param.PropertyInfo.GetValue(baby, null) == param.Value ? 1 : 0);
            }

            if (score <= bestScore) continue;
            bestScore = score;
            ret = cat;
        }
        return ret;
    }

Вы должны подумать о том, чтобы просто выполнить простую функцию сравнения, учитывая, что эти объекты не являются динамическими, это способgo:

public Cat GetBestCat(List<Cat> listOfCats, string name , int? age , bool? gender, string race ,string babyName,int? babyAge,bool? babyGender )
    {
        var ret = listOfCats[0];
        var highestScore = 0;
        foreach (var cat in listOfCats)
        {
            var score = 0;
            score += name != null && cat.Name.Equals(name) ? 1 : 0;
            score += age.HasValue && cat.Age.Equals(age.Value) ? 1 : 0;
            score += gender.HasValue && cat.Gender.Equals(gender.Value) ? 1 : 0;
            score += race != null && cat.Race.Equals(race) ? 1 : 0;
            score += name != null && cat.Name.Equals(name) ? 1 : 0;
            score += cat.Babys
                .Where(k => babyName==null || k.Name.Equals(babyName))
                .Where(k => !babyAge.HasValue || k.Age.Equals(babyAge.Value))
                .Any(k => !babyGender.HasValue || k.Gender.Equals(babyGender.Value))?1:0;
            if (score <= highestScore) continue;
            highestScore = score;
            ret = cat;
        }

        return ret;
    }
0 голосов
/ 13 ноября 2018

Ну, у меня нет возможности протестировать это решение, но вы можете попробовать это:

Предположим, у вас есть список кошек:

var cats = new List<Cat>();

Теперь вы определили, чтоВаши критерии:

var desiredName = "Micky";
var desiredAge = 42;
var desiredKitten = "Mini";

И тогда вы должны получить желаемого кота:

var desiredCat = cats
        .Select(c => new {
            Rating = 
                Convert.ToInt32(c.Age == desiredAge) +       // Here you check first criteria
                Convert.ToInt32(c.Name == desiredName) +     // Check second
                Convert.ToInt32(c.Babys.Count(b => b.Name == desiredKitten) > 0),   // And the third one
            c })
        .OrderByDescending(obj => obj.Rating) // Here you order them by number of matching criteria
        .Select(obj => obj.c) // Then you select only cats from your custom object
        .First(); // And get the first of them

Пожалуйста, проверьте, работает ли это для вас.И если вам нужен более конкретный ответ или некоторые правки для меня, чтобы добавить.

0 голосов
/ 13 ноября 2018

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

public static List<Cat> CheckProperties(List<Cat> inCatList, Cat inQueryCat)
{
    Dictionary<Cat, List<PropertyInfo>> dict = new Dictionary<Cat, List<PropertyInfo>>();

    foreach (PropertyInfo pI in inQueryCat.GetType().GetProperties())
    {
        var value = pI.GetValue(inQueryCat);

        if (value != null)
        {
            var cats = inCatList.Where(cat => cat.GetType().GetProperty(pI.Name).GetValue(cat).Equals(value));

            foreach (Cat cat in cats)
            {
                if (dict.ContainsKey(cat))
                {
                    dict[cat].Add(pI);
                }
                else
                {
                    dict.Add(cat, new List<PropertyInfo>() {pI});
                }
            }
        }
    }

    int max = Int32.MinValue;
    foreach (KeyValuePair<Cat, List<PropertyInfo>> keyValuePair in dict)
    {
        if (keyValuePair.Value.Count > max)
        {
            max = keyValuePair.Value.Count;
        }
    }

    return dict.Where(pair => pair.Value.Count == max).Select(pair => pair.Key).ToList();
}
0 голосов
/ 13 ноября 2018

Если вы действительно сравните 2 или 3 требования, вы можете упростить использование Linq следующим образом:

// try to find with 3 requirements
var foundCats = catList.Where(t => t.Name == desiredName && 
                                   t.Age == desiredAge &&
                                   t.Babys.Any(k => k.Name == desiredKitten)
                             ).ToList();

if (foundCats.Any())
{
    // you found the desired cat (or cats)
    return foundCats;
}

// try to find with 2 requirements
foundCats = catList.Where(t => 
    (t.Name == desiredName && t.Age == desiredAge) ||
    (t.Name == desiredName && t.Babys.Any(k => k.Name == desiredKitten)) ||
    (t.Age == desiredAge && t.Babys.Any(k => k.Name == desiredKitten)
).ToList();

if (foundCats.Any())
{
    // you found the desired cat (or cats)
    return foundCats;
}

// try to find with only 1 requirement
foundCats = catList.Where(t => t.Name == desiredName || 
                               t.Age == desiredAge ||
                               t.Babys.Any(k => k.Name == desiredKitten)
                         ).ToList();
return foundCats;
...