Алгоритм фильтрации коллекции - PullRequest
1 голос
/ 10 августа 2010

У меня есть объект Country, в котором есть Areas. Области имеет Провинции. В провинциях есть города, а в городах и городах есть отели.

Я хочу отфильтровать список регионов, чтобы только у объектов со свойством userHaveBeenThere было установлено значение true (районы, провинции, города и отели.

Я собираюсь связать этот список с деревом.

Худшая часть этой алгоритмической ситуации, когда, например:

регион не имеет userHaveBeenThere == true, все провинции тоже, все города тоже, но в одном из десяти отелей один из десяти отелей имеет userHaveBeenThere как true. Поэтому я должен показать пользователю этот регион с одной провинцией, с одним городом и с одним отелем.

Другая страшная вещь в том, что у меня есть два дерева. Сначала я должен показать полную структуру, а во-вторых - фильтровать, поэтому я немного напуган ссылками при использовании таких операций фильтрации, как удаление.

Итак, вопрос в том, как отфильтровать этот список?

TreeView1

Region1
-Area1
  -Province1
     -City1
     -City2
         -Hotel1
         -Hotel2
         -Hotel3
  -Province2
     -City3
     -City4
         -Hotel4
         -Hotel5
         -Hotel6
-Area2
Region2
-Area21
  -Province21
     -City21
     -City22
         -Hotel21
         -Hotel22
         -Hotel23
  -Province22
     -City23
     -City24
         -Hotel24
         -Hotel25
         -Hotel26
-Area22

Filtered list
Region1
-Area1
  -Province1
     -City2
       -Hotel3
Region2
-Area21
   -Province22
     -City24
         -Hotel24

Я не хочу отвечать, как связывать :) Только ответить, как фильтровать :)

Это мое решение:

 var copiedCountry = CloneObject(_package.Country);


            for (int indexOfRegion = 0; indexOfRegion < copiedCountry.ListOfRegions.Count; indexOfRegion++)
            {
                var region = copiedCountry.ListOfRegions[indexOfRegion];
                if (region.ListOfProvinces.Count > 0)
                {
                    for (int indexOfProvince = 0; indexOfProvince < region.ListOfProvinces.Count; indexOfProvince++)
                    {
                        var province = region.ListOfProvinces[indexOfProvince];
                        if (province.ListOfCities.Count > 0)
                        {
                            for (int indexOfCity = 0; indexOfCity < province.ListOfCities.Count; indexOfCity++)
                            {
                                var city = province.ListOfCities[indexOfCity];
                                int numberOfHotels = city.ListOfHotels.Count;
                                for (int indexOfHotel = 0; indexOfHotel < numberOfHotels; indexOfHotel++)
                                {
                                    var hotel = city.ListOfHotels[indexOfHotel];
                                    if (hotel.userHaveBeenThere  == false)
                                    {
                                        city.ListOfHotels[indexOfHotel] = null;
                                    }
                                }

                                city.ListOfHotels.RemoveAll(h => h == null);

                                if (city.ListOfHotels.Where(h => h.userHaveBeenThere  == true).Count() > 0)
                                {

                                }
                                else
                                {
                                    if (city.userHaveBeenThere  == false)
                                    {
                                        province.ListOfCities[indexOfCity]=null;
                                    }

                                }
                            }

                            province.ListOfCities.RemoveAll(c => c == null);

                            if (province.ListOfCities.Count == 0)
                            {
                                if (province.userHaveBeenThere  == false)
                                {
                                    region.ListOfProvinces[indexOfProvince]=null;
                                }
                            }



                        }
                        else
                        {
                            if (province.userHaveBeenThere  == false)
                            {
                                region.ListOfProvinces[indexOfProvince] = null;
                            }
                        }
                    }

                    region.ListOfProvinces.RemoveAll(p => p == null);

                    if (region.ListOfProvinces.Count == 0)
                    {
                        if (region.userHaveBeenThere  == false)
                        {
                            copiedCountry.ListOfRegions[indexOfRegion]=null;
                        }
                    }
                }
                else
                {
                    if (region.userHaveBeenThere  == false)
                    {
                        copiedCountry.ListOfRegions[indexOfRegion]=null;
                    }
                }

                copiedCountry.ListOfRegions.RemoveAll(r => r == null);
            }


public static T CloneObject<T>(T item)
        {
            using (MemoryStream ms = new MemoryStream())
            {

                BinaryFormatter bf = new BinaryFormatter(null,
                          new StreamingContext(StreamingContextStates.Clone));

                try
                {
                    bf.Serialize(ms, item);
                }
                catch (Exception e)
                {
                    throw;
                }


                ms.Seek(0, SeekOrigin.Begin);


                return (T)bf.Deserialize(ms);
            }
        }

Ответы [ 5 ]

1 голос
/ 13 августа 2010

Вместо использования bool, чтобы узнать, был ли пользователь там, подумайте об использовании bool ?.Установите его в null, если вы хотите перенаправить на дочерний объект userHasBeenThere .

. Вот конкретный пример, магия происходит, когда вы устанавливаете один из объектов этого 100 * ** true.

Вот пример шаблона:

public abstract class AUserTracker
{
    private IEnumerable<AUserTracker> _children;
    public IEnumerable<AUserTracker> Children
    {
        get { return _children; }
        set { _children = value; }
    }

    private bool? _userHasBeenThere;
    public bool UserHasBeenThere
    {
        get
        {
            if (_userHasBeenThere == null)
            {
                _userHasBeenThere = false;
                // Uses OR operator, any child will trigger the show up.
                foreach (AUserTracker child in Children)
                    _userHasBeenThere |= child.UserHasBeenThere;
            }
            return _userHasBeenThere ?? false;
        }
    }
}

Это будет базовый класс для всех ваших объектов.Затем вы можете использовать WPF HierarchicalDatatemplate , чтобы показать ваши объекты в TreeView .

{наслаждайтесь}

1 голос
/ 10 августа 2010

Данные хранятся в базе данных или хранятся в виде графика?

Если это база данных, вы можете настроить запросы для получения правильных данных.

Если это график, вы можете сделать его двунаправленным, начать снизу (посещенные отели) и пройти к каждому корню (регионам), вставив родителей в новый объект.

1 голос
/ 10 августа 2010

Я бы предложил использовать рекурсию. Для узла, который может быть Страна, Провинция, Город, Отель, выполните следующие действия:

bool ShouldDisplayNode(Node n){
    if (n.Type == Hotel){
        return n.HasBeenThere;
    }
    bool display = false;
    foreach (var child in n.Children){
        display |= ShouldDisplayNode(child);
    } 
    return display;
}

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

1 голос
/ 10 августа 2010

Можете ли вы добавить ко всем вашим объектам переменную "BeenThereInHere" (или любое другое имя, которое вы хотите), который будет установлен в значение true, если один из его детей имеет userHaveBeenThere == true, таким образом, вы можете быстро определить, куда сканировать и где вы можете пропустить его, чтобы сэкономить время.

0 голосов
/ 11 августа 2010

Это мое решение:

 var copiedCountry = CloneObject(_package.Country);


            for (int indexOfRegion = 0; indexOfRegion < copiedCountry.ListOfRegions.Count; indexOfRegion++)
            {
                var region = copiedCountry.ListOfRegions[indexOfRegion];
                if (region.ListOfProvinces.Count > 0)
                {
                    for (int indexOfProvince = 0; indexOfProvince < region.ListOfProvinces.Count; indexOfProvince++)
                    {
                        var province = region.ListOfProvinces[indexOfProvince];
                        if (province.ListOfCities.Count > 0)
                        {
                            for (int indexOfCity = 0; indexOfCity < province.ListOfCities.Count; indexOfCity++)
                            {
                                var city = province.ListOfCities[indexOfCity];
                                int numberOfHotels = city.ListOfHotels.Count;
                                for (int indexOfHotel = 0; indexOfHotel < numberOfHotels; indexOfHotel++)
                                {
                                    var hotel = city.ListOfHotels[indexOfHotel];
                                    if (hotel.userHaveBeenThere  == false)
                                    {
                                        city.ListOfHotels[indexOfHotel] = null;
                                    }
                                }

                                city.ListOfHotels.RemoveAll(h => h == null);

                                if (city.ListOfHotels.Where(h => h.userHaveBeenThere  == true).Count() > 0)
                                {

                                }
                                else
                                {
                                    if (city.userHaveBeenThere  == false)
                                    {
                                        province.ListOfCities[indexOfCity]=null;
                                    }

                                }
                            }

                            province.ListOfCities.RemoveAll(c => c == null);

                            if (province.ListOfCities.Count == 0)
                            {
                                if (province.userHaveBeenThere  == false)
                                {
                                    region.ListOfProvinces[indexOfProvince]=null;
                                }
                            }



                        }
                        else
                        {
                            if (province.userHaveBeenThere  == false)
                            {
                                region.ListOfProvinces[indexOfProvince] = null;
                            }
                        }
                    }

                    region.ListOfProvinces.RemoveAll(p => p == null);

                    if (region.ListOfProvinces.Count == 0)
                    {
                        if (region.userHaveBeenThere  == false)
                        {
                            copiedCountry.ListOfRegions[indexOfRegion]=null;
                        }
                    }
                }
                else
                {
                    if (region.userHaveBeenThere  == false)
                    {
                        copiedCountry.ListOfRegions[indexOfRegion]=null;
                    }
                }

                copiedCountry.ListOfRegions.RemoveAll(r => r == null);
            }


public static T CloneObject<T>(T item)
        {
            using (MemoryStream ms = new MemoryStream())
            {

                BinaryFormatter bf = new BinaryFormatter(null,
                          new StreamingContext(StreamingContextStates.Clone));

                try
                {
                    bf.Serialize(ms, item);
                }
                catch (Exception e)
                {
                    throw;
                }


                ms.Seek(0, SeekOrigin.Begin);


                return (T)bf.Deserialize(ms);
            }
        }

Я думаю, что есть что оптимизировать: /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...