Фильтрация списка WPF - PullRequest
       1

Фильтрация списка WPF

2 голосов
/ 05 мая 2011

Я новичок в WPF, так что это, вероятно, простой вопрос.У меня есть приложение, которое читает некоторые слова из файла CSV и сохраняет их в списке строк.То, что я пытаюсь сделать, это параметризовать этот список, чтобы показать наиболее популярные слова в моем списке.Поэтому в моем пользовательском интерфейсе я хочу иметь текстовое поле, которое при вводе числа, например, 5, отфильтровывает исходный список, оставляя только 5 самых популярных (часто встречающихся) слов в новом списке.Кто-нибудь может помочь с этим последним шагом?Спасибо -

public class VM
{
    public VM()
    {
        Words = LoadWords(fileList);
    }

    public IEnumerable<string> Words { get; private set; }

    string[] fileList = Directory.GetFiles(@"Z:\My Documents\", "*.csv");


    private static IEnumerable<string> LoadWords(String[] fileList)
    {

        List<String> words = new List<String>();
        //
        if (fileList.Length == 1)
        {

            try
            {
                foreach (String line in File.ReadAllLines(fileList[0]))
                {
                    string[] rows = line.Split(',');

                    words.AddRange(rows);
                }

            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "Problem!");
            }

        }

        else
        {
            System.Windows.MessageBox.Show("Please ensure that you have ONE read file in the source folder.", "Problem!");

        }
        return words;
    }

}

Ответы [ 4 ]

1 голос
/ 05 мая 2011

Вы можете использовать CollectionViewSource.GetDefaultView(viewModel.Words), что возвращает ICollectionView.

ICollectionView предоставляет Filter свойство типа Predicate<object>, которое вы можете задействовать для фильтрации.

Таким образом, общий сценарий выглядит следующим образом:

  1. ViewModel предоставляет свойство PopularCount, которое привязано к некоторому текстовому полю в View.
  2. ViewModel прослушивает изменение свойства PopularCount.
  3. Когда происходит уведомление, модель получает ICollectionView для коллекции viewModel.Words и устанавливает свойство Filter.

Вы можете найти рабочий пример использования свойства Filter здесь .Если вы застряли с кодом, дайте мне знать.

1 голос
/ 05 мая 2011

LINQ-запрос, который группирует по слову, а порядок по количеству по убыванию этого слова, должен делать это.Попробуйте это

private static IEnumerable<string> GetTopWords(int Count)
{
    var popularWords = (from w in words                
          group w by w
          into grp
          orderby grp.Count() descending
          select grp.Key).Take(Count).ToList();
    return popularWords;
}
0 голосов
/ 05 мая 2011

Вместо того, чтобы читать все слова в списке и затем сортировать его по частоте, более чистый подход будет состоять в создании пользовательского класса MyWord, который хранит слово и частоту. При чтении файла частота слова может быть увеличена. Класс может реализовать IComparable<T> для сравнения слов на основе частоты.

public class MyWord : IComparable<MyWord>
{
    public MyWord(string word)
    {
        this.Word = word;
        this.Frequency = 0;
    }

    public MyWord(string word, int frequency)
    {
        this.Word = word;
        this.Frequency = frequency;
    }

    public string Word { get; private set;}        
    public int Frequency { get; private set;}

    public void IncrementFrequency()
    {
        this.Frequency++;
    }

    public void DecrementFrequency()
    {
        this.Frequency--;
    }

    public int CompareTo(MyWord secondWord)
    {
        return this.Frequency.CompareTo(secondWord.Frequency);
    }
}

Основной класс VM будет иметь этих членов,

public IEnumerable<MyWord> Words { get; private set; }

private void ShowMostPopularWords(int numberOfWords)
{
    SortMyWordsDescending();
    listBox1.Items.Clear();

    for (int i = 0; i < numberOfWords; i++ )
    {
        listBox1.Items.Add(this.Words.ElementAt(i).Word + "|" + this.Words.ElementAt(i).Frequency);
    }
}

И звонок на ShowMostPopularWords()

private void Button_Click(object sender, RoutedEventArgs e)
{
    int numberOfWords;
    if(Int32.TryParse(textBox1.Text, NumberStyles.Integer, CultureInfo.CurrentUICulture, out numberOfWords))
    {
        ShowMostPopularWords(numberOfWords);
    }
}
0 голосов
/ 05 мая 2011

Я не уверен, что группировка и упорядочение списка «слов» - это то, что вам нужно, но если да, это может быть способом сделать это:

    int topN = 3;
    List<string> topNWords = new List<string>();

    string[] words = new string[] {
        "word5",
        "word1",
        "word1",
        "word1",
        "word2",
        "word2",
        "word2",
        "word3",
        "word3",
        "word4",
        "word5",
        "word6",
    };

    // [linq query][1] 
    var wordGroups = from s in words
                       group s by s into g
                       select new { Count = g.Count(), Word = g.Key };

    for (int i = 0; i < Math.Min(topN, wordGroups.Count()); i++)
    {
        // (g) => g.Count is a [lambda expression][2]
        // .OrderBy and Reverse are IEnumerable extension methods
        var element = wordGroups.OrderBy((g) => g.Count).Reverse().ElementAt(i);
        topNWords.Add(element.Count + " - " + element.Word);
    }

Это можно сделать намного корочеиспользуя порядок в предложении linq select, но я хотел бы познакомить вас со встроенными лямбдами и другими расширениями.

Короткая версия может быть:

topNWords = (from s in words                
          group s by s
          into g
          orderby g.Count() descending
          select g.Key).Take(Math.Min(topN, g.Count()).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...