innomotion media
innomotion media

Reputation: 922

C#, Android: Search every element of a list with a string and return elements sorted by number of matching characters

Oh boy, this is a tough one:

I have my list:

    private List<Tasks> tasks;

Now, I made an edittext where users can type in a string that is supposed to search every element in within my list "tasks" if the names match the search request. If true, it is supposed to write all those matching elements onto a textview and display them sorted by matching rate.

Say im searching for "ska" in my list with the elements

  1. Skooma
  2. Skate
  3. Style
  4. Halfpipe

It is supposed to return in that order:

  1. Skate (three character are matching)
  2. Skooma ( two are matching )
  3. Style ( only the S is matching )

This is how far I have gotten ( not much, yes ...)

    private string SearchList(string search)
    {
        string res = null;

        tasks = Libary.Instance.getTasksBasedOnSubCategory(1);

        bool itemExists = tasks.Any(x => x.Name == search);

        return res; 
    }

How would you guys go on about this? Thanks :)

// MY SOLUTION

Thanks to you, this is what I did ( just for completition ...)

private void FormatListToString(string search)
        {
            linLayResults.RemoveAllViews();

            for (int x = 0; x < 40; x++) // in jeder sub suchen... könnte dauern und statisch
            {

                tasks = Libary.Instance.getTasksBasedOnSubCategory(x);

                List<string> stringlist = new List<string>();

                foreach (var task in tasks )
                {
                    stringlist.Add(task.Name.ToLower().ToString());
                }

                SortingList(stringlist, search);

            }
        }

        private void SortingList(List<string> list, string keyword)
        {
            IEnumerable<string> filterLst = list.Where
                (s => s.Contains(keyword.ToLower().ToString()));

            var result = filterLst.OrderBy(s => !s.StartsWith(keyword, StringComparison.OrdinalIgnoreCase))
                 .ThenBy(s => !s.ToLower().Contains(keyword));

            foreach (string s in result)
            {
                FormatTextView(s);
            }

        }

        private void FormatTextView(string s)
        {
            TextView xy = new TextView(this);
            xy.Text = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s);

            xy.SetTypeface(font, TypefaceStyle.Normal);
            xy.SetTextColor(Color.ParseColor("#000000"));
            xy.TextSize = 18;
            xy.SetPadding(Resources.DisplayMetrics.WidthPixels / 50,
                          intHeightOfDisplay / 50, 0, 0);

            xy.Click += delegate
            {

            };

            linLayResults.AddView(xy);
        }

Converted all the lists that I needed into a string List, then used the edittext to find it per keyword. removed all uppercases. Then put it all into a textview that reenabled the uppercases on every first letter of every string.

AWESOME!

Upvotes: 0

Views: 69

Answers (2)

ASh
ASh

Reputation: 35730

I would use helper function to evaluate a match between word and search parameter:

private static int GetMatchScore(string word, string pattern)
{
    return pattern.TakeWhile((c, i) => i < word.Length && 
                                       Char.ToLower(c) == Char.ToLower(word[i]))
                  .Count();
}

GetMatchScore returns the number of matching letters at the beginning of word

the query to find and order matches would look like this:

var words = new List<string>{ "Skooma", "Skate", "Style", "Halfpipe" };
string filter = "Ska";  

var search = words.Select(word => new {word, score = GetMatchScore(word, filter)})
                  .Where(m => m.score > 0)
                  .OrderByDescending(m => m.score)
                  .Select(m => m.word);

Upvotes: 1

NSKBpro
NSKBpro

Reputation: 383

Maybe not a clean but its a working solution.

public void SortingList(List<string> list,string keyword)
        {
            IEnumerable<string> filterLst = list.Where(s => s.StartsWith(keyword[0].ToString(), StringComparison.OrdinalIgnoreCase));

            var result = filterLst.OrderBy(s => !s.StartsWith(keyword, StringComparison.OrdinalIgnoreCase))
                 .ThenBy(s => !s.ToLower().Contains(keyword));

            foreach (string s in result)
            {
                Console.WriteLine(s);
            }

        }

Upvotes: 2

Related Questions