Windows phone app t9 predictive text - c#

I am working on a windows phone app, which is a dialer and I have few problems with the predictive text. Predictive text works fine but it's laggy and slow. My code is:
I've put a contact search function in the textbox's text changed event:
private void dialer_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
MainPage.DialerText = dialer.Text;
contactSearch(MainPage.DialerText);
}
catch (Exception f)
{
MessageBox.Show(f.Message);
}
}
ContactSearch function code:
public void contactSearch(string str)
{
try
{
var digitMap = new Dictionary<int, string>() {
{ 1, "" },
{ 2, "[abcABC]" },
{ 3, "[defDEF]" },
{ 4, "[ghiGHI]" },
{ 5, "[jklJKL]" },
{ 6, "[mnoMNO]" },
{ 7, "[pqrsPQRS]" },
{ 8, "[tuvTUV]" },
{ 9, "[wxyzWXYZ]" },
{ 0, "" },
};
var enteredDigits = str;
var charsAsInts = enteredDigits.ToCharArray().Select(x => int.Parse(x.ToString()));
var regexBuilder = new StringBuilder();
foreach (var val in charsAsInts)
regexBuilder.Append(digitMap[val]);
var pattern = regexBuilder.ToString();
//append a ".*" to the end of the regex to make it "StartsWith", beginning for "EndsWith", or both for "Contains";
pattern = ".*" + pattern + ".*";
SearchListbox.ItemsSource = listobj.FindAll(x => x.PhoneNumbers.Contains(str) | Regex.IsMatch(x.FirstName, pattern));
}
catch (Exception e)
{
// MessageBox.Show(e.Message);
}
}
This code works fine but laggy and slow. I need to make it faster. Please suggest some improvements. Thank you.

These solutions can improve it:
1- Don't use Try catch for repeatedly functions:
This can slow down the performance easily, instead try using if else
2 - Use an asynchronous Task:
It's great for not blocking UI and avoids lag and crashes but use a low delay time for your task e.g 50ms;
3- Use other collection types:
As i can see in your code , your dictionary key is int started regularly from 1.
So why don't you use a array or list which are much faster with more items.
Like this:
string[] contacts = {"contact 1","contact 2","contact 3","contact 4"};
Or even a list:
List<string> contacts = new List<string>();
contacts.Add("contact 1");
contact.Add("contact 2");
Note that Changing collection type may increase performance only in huge amounts of data.

public interface ICellT9
{
void Add(string a_name);
List<string> GetNames(string a_number);
}
public class Cell : ICellT9
{
private Dictionary<int, Cell> m_nodeHolder;
private List<string> m_nameList;
public Cell()
{
m_nodeHolder = new Dictionary<int, Cell>();
for (int i = 2; i < 10; i++)
{
m_nodeHolder.Add(i, null);
}
}
public void Add(string a_name)
{
Add(a_name, a_name);
}
private void Add(string a_name, string a_originalName)
{
if ((string.IsNullOrEmpty(a_name) == true) && (string.IsNullOrEmpty(a_originalName) == false))
{
if (m_nameList == null)
{
m_nameList = new List<string>();
}
m_nameList.Add(a_originalName);
}
else
{
int l_firstNumber = CharToNumber(a_name[0].ToString());
if (m_nodeHolder[l_firstNumber] == null)
{
m_nodeHolder[l_firstNumber] = new Cell();
}
m_nodeHolder[l_firstNumber].Add(a_name.Remove(0, 1), a_originalName);
}
}
public List<string> GetNames(string a_number)
{
List<string> l_result = null;
if (string.IsNullOrEmpty(a_number))
{
return l_result;
}
int l_firstNumber = a_number[0] - '0';
if (a_number.Length == 1)
{
l_result = m_nodeHolder[l_firstNumber].m_nameList;
}
else if(m_nodeHolder[l_firstNumber] != null)
{
l_result = m_nodeHolder[l_firstNumber].GetNames(a_number.Remove(0, 1));
}
return l_result;
}
private int CharToNumber(string c)
{
int l_result = 0;
if (c == "a" || c == "b" || c == "c")
{
l_result = 2;
}
else if (c == "d" || c == "e" || c == "f")
{
l_result = 3;
}
else if (c == "g" || c == "h" || c == "i")
{
l_result = 4;
}
else if (c == "j" || c == "k" || c == "l")
{
l_result = 5;
}
else if (c == "m" || c == "n" || c == "o")
{
l_result = 6;
}
else if (c == "p" || c == "q" || c == "r" || c == "s")
{
l_result = 7;
}
else if (c == "t" || c == "u" || c == "v")
{
l_result = 8;
}
else if (c == "w" || c == "x" || c == "y" || c == "z")
{
l_result = 9;
}
return l_result;
}
}

Related

how to order result by displaying each job type by order

I have a search query which search for all jobs in the database and than displays them in accordance to the most recent ones filtering the data by date as follows:
result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation)).ToList());
result = (from app in result orderby DateTime.ParseExact(app.PostedDate, "dd/MM/yyyy", null) descending select app).ToList();
result = GetAllJobModelsOrder(result);
after that I have a method GetAllJobModelsOrder which displays jobs in order which seems to be work fine but in my case its not ordering jobs so I need to understand where I am wrong:
private List<AllJobModel> GetAllJobModelsOrder(List<AllJobModel> result)
{
var list = result.OrderBy(m => m.JobImage.Contains("job1") ? 1 :
m.JobImage.Contains("job2") ? 2 :
m.JobImage.Contains("job3") ? 3 :
m.JobImage.Contains("job4") ? 4 :
m.JobImage.Contains("job5") ? 5 :
6)
.ToList();
return list;
}
The result I get is about 10 jobs from job1 and than followed by other jobs in the same order what I would like to achieve is to filter the most recent jobs than display one job from each type of a job.
An example of the input would be as follows:
AllJobModel allJobModel = new AllJobModel
{
JobDescription = "Description",
JobImage = "Job1",
JobTitle = "title",
locationName = "UK",
datePosted = "15/06/2020",
}
The output that I get is as follows:
In where result should be mixed from different jobs.
Excepted resulta as follows a specific order of job source--1. TotalJob[0] :: 2. MonsterJob[0] :: 3. Redd[0] :: 4. TotalJob[ 1 ] :: 5. MonsterJob[ 1 ] ::6. Redd[ 1 ]:
I have tried the following solution but list data structure seems to be not stroing data in order:
private List<AllJobModel> GetAllJobModelsOrder(List<AllJobModel> result)
{
string lastItem = "";
List<AllJobModel> list = new List<AllJobModel>();
int pos = -1;
while(result.Count != 0)
{
for(int i = 0; i < result.Count; i++)
{
if(result[i].JobImage.Contains("reed") && (lastItem == "" || lastItem == "total" || lastItem == "monster"))
{
pos++;
list.Insert(pos,result[i]);
lastItem = "reed";
result.Remove(result[i]);
break;
}else if (result[i].JobImage.Contains("total") && (lastItem == "reed" || lastItem == "monster" || lastItem == "" ))
{
pos++;
list.Insert(pos, result[i]);
lastItem = "total";
result.Remove(result[i]);
break;
}else if(result[i].JobImage.Contains("monster.png") && (lastItem =="total" || lastItem == "reed" || lastItem == "" ))
{
pos++;
list.Insert(pos, result[i]);
lastItem = "monster";
result.Remove(result[i]);
break;
}else if(result[i].JobImage.Contains("reed") &&( lastItem == "reed"))
{
if(result.FirstOrDefault(a=>a.JobImage.Contains("total") || a.JobImage.Contains("monster")) != null)
{
lastItem = "total";
break;
}
else
{
pos++;
list.Insert(pos, result[i]);
lastItem = "reed";
result.Remove(result[i]);
break;
}
}
else if (result[i].JobImage.Contains("total") && (lastItem == "total"))
{
if (result.FirstOrDefault(a => a.JobImage.Contains("reed") || a.JobImage.Contains("monster")) != null)
{
lastItem = "monster";
break;
}
else
{
pos++;
list.Insert(pos, result[i]);
lastItem = "total";
result.Remove(result[i]);
break;
}
}
else if (result[i].JobImage.Contains("monster") && (lastItem == "monster"))
{
if (result.FirstOrDefault(a => a.JobImage.Contains("total") || a.JobImage.Contains("reed")) != null)
{
lastItem = "reed";
break;
}
else
{
pos++;
list.Insert(pos, result[i]);
lastItem = "monster";
result.Remove(result[i]);
break;
}
}
}
}
return list;
}
also what I found is that the value of the elements in the list is different from what its actual value. So I am not sure if this is an error with my code or with visual studio:
you can use the below concept here. I am sorting a list based on the numeric value at the end of each string value using Regex.
List<string> ls = new List<string>() { "job2", "job1", "job4", "job3" };
ls = ls.OrderBy(x => Regex.Match(x, #"\d+$").Value).ToList();
Certainly the requirement was not as straight forward as initially thought. Which is why I am offering a second solution.
Having order by and rotate the offering "Firm" in a type of priority list for a set number of times and then just display whatever comes after that requires a custom solution. If the one algorithm you have works and you are happy then great. Otherwise, I have come up with this algorithm.
private static List<AllJobModel> ProcessJobs(List<AllJobModel> l)
{
var noPriorityFirst = 2;
var orderedList = new List<AllJobModel>();
var priorityImage = new string[] { "TotalJob", "MonsterJob", "Redd" };
var gl = l.OrderBy(o => o.datePosted).GroupBy(g => g.datePosted).ToList();
foreach (var g in gl)
{
var key = g.Key;
for (int i = 0; i < noPriorityFirst; i++)
{
foreach (var j in priorityImage)
{
var a = l.Where(w => w.datePosted.Equals(key) && w.JobImage.Equals(j)).FirstOrDefault();
if (a != null)
{
orderedList.Add(a);
var ra = l.Remove(a);
}
}
}
foreach (var j in l.ToList())
{
var a = l.Where(w => w.datePosted.Equals(key)).FirstOrDefault();
if (a != null)
{
orderedList.Add(a);
var ra = l.Remove(a);
}
}
}
return orderedList;
}
To test this process I have created this Console app:
static void Main(string[] args)
{
Console.WriteLine("Start");
var l = CreateTestList();
var lJobs = ProcessJobs(l);
lJobs.ForEach(x => Console.WriteLine($"{x.datePosted} : {x.JobImage}"));
}
private static List<AllJobModel> CreateTestList()
{
var orderedList = new List<AllJobModel>();
var l = new List<AllJobModel>();
var priorityImage = new string[] { "TotalJob", "MonsterJob", "Redd" };
var rand = new Random();
var startTime = DateTime.Now;
for (int i = 0; i < 20; i++)
{
var j = rand.Next(0, priorityImage.Length);
var h = rand.Next(0, 4);
var a = new AllJobModel();
a.JobDescription = "Desc " + i;
a.JobImage = priorityImage[j];
a.JobTitle = "Title" + i;
a.locationName = "UK";
a.datePosted = startTime.AddDays(h);
l.Add(a);
}
for (int i = 0; i < 20; i++)
{
var j = rand.Next(0, priorityImage.Length);
var h = rand.Next(0, 4);
var a = new AllJobModel();
a.JobDescription = "Desc " + i;
a.JobImage = "Job " + i;
a.JobTitle = "Title" + i;
a.locationName = "UK";
a.datePosted = startTime.AddDays(h);
l.Add(a);
}
return l;
}

Split a comma delimited string with nested children in parentheses

I have a string formatted something like this: "a, b(c,d(e,f),g),h, i(j, k, l)"
where each letter represents one or more words.
I need to split this string up in to a list of objects:
public class Item
{
public string Name { get; set; }
public IEnumerable<Item> Children { get; set; }
public Ingredient()
{
Children = new List<Item>();
}
}
The desired result represented in an outline format:
a
b
2.1. c
2.2. d
2.2.1. e
2.2.2. f
2.3. g
h
i
4.1. j
4.2. k
4.2. l
What would be the most efficient way to do so?
You can use a recursive algorithm to parse your string like this:
static IEnumerable<Item> Parse(string source)
{
var root = new Item() { Name = "Root", Children = new List<Item>() };
AddChildrenTo(root, source);
return root.Children;
}
static int AddChildrenTo(Item item, string source)
{
Item node = null;
var word = new List<char>();
for (int i = 0; i < source.Length; i++)
{
var c = source[i];
if (new[] { ',', '(', ')' }.Contains(c))
{
if (word.Count > 0)
{
node = new Item { Name = new string(word.ToArray()), Children = new List<Item>() };
(item.Children as List<Item>).Add(node);
word.Clear();
}
if (c == '(')
{
i += AddChildrenTo(node, source.Substring(i + 1)) + 1;
}
else if (c == ')')
{
return i;
}
}
else if (char.IsLetter(c)) // add other valid characters to if condition
{
word.Add(c);
}
}
return source.Length;
}
Then you can simply call Parse() (For better demonstration I've changed the letters (a, b, ..) in your string to words (ark, book, ...)):
string source = "ark,book(cook,door(euro,fun),good),hello,ink(jack,kill,loop)";
var res = Parse(source);
Please note that for a very large string recursive approach wouldn't be the best solution. And for simplicity I didn't do the error checkings.
You can use a stack like this:
static public List<Item> Parse(string str)
{
Stack<Item> stack = new Stack<Item>();
Item root = new Item();
stack.Push(root);
foreach (char c in str)
{
if (char.IsLetter(c))
{
Item item = new Item();
item.Name = c.ToString();
stack.Peek().Children.Add(item);
stack.Push(item);
}
else if (c == ')' || c == ',')
{
stack.Pop();
}
}
return root.Children;
}
Please note that the Children property needs to be a List like this:
public class Item
{
public string Name { get; set; }
public List<Item> Children { get; set; }
public Item()
{
Children = new List<Item>();
}
}
If you don't care about unbalanced bracket type:
static string[] SplitString(string input)
{
bool nSingleQuote = false;
bool nDubbleQuote = false;
int nBracket = 0;
int start = 0;
List<String> result = new List<String>();
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (c == '\'')
{
if(!nDubbleQuote) nSingleQuote = !nSingleQuote;
}
else if (c == '"')
{
if(!nSingleQuote) nDubbleQuote = !nDubbleQuote;
}
if (!nSingleQuote && !nDubbleQuote)
{
if (c == ',')
{
if (nBracket == 0)
{
result.Add(input.Substring(start, i - start).Trim());
start = i + 1;
}
}
else if (c == '(' || c == '[' || c == '{')
{
nBracket++;
}
else if (c == ')' || c == ']' || c == '}')
{
nBracket--;
if (nBracket < 0)
throw new Exception("Unbalanced parenthesis, square bracket or curly bracket at offset #" + i);
}
}
}
if (nBracket > 0)
throw new Exception("Missing closing parenthesis, square bracket or curly bracket");
if (nSingleQuote || nDubbleQuote)
throw new Exception("Missing end quotation mark");
result.Add(input.Substring(start).Trim());
return result.ToArray();
}

Trying to make a random selector with no repeats. It works, but only 4 times? (C# windows form)

As the title says, I'm trying to make a piece of code that will randomly select a group (A-H) with no repeats in a windows form using C#. It seems to work, but after 4 times it will return that all groups have been selected. When I remove the line of code to output that they've been selected then I get an infinite loop instead. Anyone see what my issue may be?
public Form1()
{
InitializeComponent();
}
//these booleans are set to true if the group has already been selected
bool A = false;
bool B = false;
bool C = false;
bool D = false;
bool E = false;
bool F = false;
bool G = false;
bool H = false;
private void selectButton_Click(object sender, EventArgs e)
{
string selection = "error";
while (selection == "error")
{
int group = RandomNumber();
if (group == 1 && A == false)
{
selection = "A";
A = true;
}
else if (group == 2 && B == false)
{
selection = "B";
B = true;
}
else if (group == 3 && C == false)
{
selection = "C";
C = true;
}
else if (group == 4 && D == false)
{
selection = "D";
D = true;
}
else if (group == 5 && E == false)
{
selection = "E";
E = true;
}
else if (group == 6 && F == false)
{
selection = "F";
F = true;
}
else if (group == 7 && G == false)
{
selection = "G";
G = true;
}
else if (group == 8 && H == false)
{
selection = "H";
H = true;
}
else if (A == true && B == true && C == true && D == true && E == true && F == true && G == true && H == true)
{
selection = "all have been selected";
}
//else
// {
// selection = "oops";
// };
};
outputRichTextBox.Text = selection;
}
private int RandomNumber()
{
Random rnd = new Random();
int num = rnd.Next(1, 9);
return num;
}
}
}
You shouldn't recreate a Random for every use. Make it an instance or static field instead.
private Random rnd = new Random();
private int RandomNumber()
{
int num = rnd.Next(1, 9);
return num;
}
On top of that, you'd probably be better-off using an array to store your values. That would just make your code a bit more readable.
Just for the sake of making this a little easier to understand, this is what I would do.
public Form1()
{
var poss = (new [] { "A", "B", "C", "D", "E", "F", "G", "H" })
.OrderBy(c => RandomNumber())
.GetEnumerator();
}
private IEnumerator<string> selections;
private Random rnd = new Random();
private void selectButton_Click(object sender, EventArgs e)
{
if (selections.MoveNext())
outputRichTextBox.Text = selections.Current;
else
outputRichTextBox.Text = "all have been selected";
}
private int RandomNumber()
{
int num = rnd.Next();
return num;
}
The idea here is to create and randomize the list at the beginning (through ordering by a random number), then loop through on each click until that list is empty.
First Random in .NET does not generate a real random number and based on the seed you pass to it's constructor, it can generate the exact series again and again. It's not a bug. It is designed so for testing your app against pseudo-random series of data, you must use RNGCryptoServiceProvider for generating a real random number:
public class SampleRandomNumber
{
static readonly object Lock = new object();
static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider();
public static int NextInt32()
{
lock (Lock)
{
var bytes = new byte[4];
Random.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
}
}
}
And NextInt32 gives us an int (including even negative numbers; of-course you can just use the abs of it).

Iterate through specific col in DGVs' & compare the string values

I got 2 datagrid views, First datagrid 1st col or Index 0 & the Second datagrid 1st col or Index 0.
How can i loop through a specific col in the datagridviews and look for the string values,if it matches with the list then go to a function.
My approach is not working. How can i do this?
private void b_calculate_Click(object sender, EventArgs e)
{
List<string> value = new List<String>() { "AE0", "AT1", "AT2", "AT3"};
value = new List<string>(datagridview1.Columns[0].Index);
List<string> value2 = new List<String>() { "BE0", "BT1", "BT2", "BT3"};
value2 = new List<string>(datagridview2.Columns[0].Index);
//First Combination
if((value.ToString() == "AT1" || value.ToString() == "AE0" ||
value.ToString() == "AT2")
&&
(value2.ToString() == "BT1" || value2.ToString() == "BE0"))
{
gottoFunction1();
}
//Second Combination
if((value.ToString() == "AT1" || value.ToString() == "AT2" )
&&
(value2.ToString() == "BT1" || value2.ToString() == "BT2"))
{
gottoFunction2();
}
}
Here's a routine that iterates through all available rows in both DataGridViews and does the processing shown in your method:
private void b_calculate_Click(object sender, EventArgs e)
{
for (var i = 0; i < dataGridView1.RowCount; i++)
{
if (dataGridView2.RowCount <= i)
break;
var cellFromDG1 = dataGridView1.Rows[i].Cells[0];
var cellFromDG2 = dataGridView1.Rows[i].Cells[0];
if (cellFromDG1.Value == null || cellFromDG2.Value == null)
{
// this could be the empty row that allows you to
// enter a new record
continue;
}
var value = cellFromDG1.Value.ToString();
var value2 = cellFromDG2.Value.ToString();
if ((value == "AT1" || value == "AE0" || value == "AT2") &&
(value2 == "BT1" || value2 == "BE0"))
{
gottoFunction1();
}
if ((value == "AT1" || value == "AT2") &&
(value2 == "BT1" || value2 == "BT2"))
{
gottoFunction2();
}
}
}

Any libraries to convert number Pinyin to Pinyin with tone markings?

Just wondering if anyone knows of a class library that can convert Chinese Pinyin to ones with tones, such as nin2 hao3 ma to nín hǎo ma. It would be similar to this answer, but hopefully using the .NET framework.
Here is my porting of #Greg-Hewgill python algorithm to C#. I haven't run into any issues so far.
public static string ConvertNumericalPinYinToAccented(string input)
{
Dictionary<int, string> PinyinToneMark = new Dictionary<int, string>
{
{0, "aoeiuv\u00fc"},
{1, "\u0101\u014d\u0113\u012b\u016b\u01d6\u01d6"},
{2, "\u00e1\u00f3\u00e9\u00ed\u00fa\u01d8\u01d8"},
{3, "\u01ce\u01d2\u011b\u01d0\u01d4\u01da\u01da"},
{4, "\u00e0\u00f2\u00e8\u00ec\u00f9\u01dc\u01dc"}
};
string[] words = input.Split(' ');
string accented = "";
string t = "";
foreach (string pinyin in words)
{
foreach (char c in pinyin)
{
if (c >= 'a' && c <= 'z')
{
t += c;
}
else if (c == ':')
{
if (t[t.Length - 1] == 'u')
{
t = t.Substring(0, t.Length - 2) + "\u00fc";
}
}
else
{
if (c >= '0' && c <= '5')
{
int tone = (int)Char.GetNumericValue(c) % 5;
if (tone != 0)
{
Match match = Regex.Match(t, "[aoeiuv\u00fc]+");
if (!match.Success)
{
t += c;
}
else if (match.Groups[0].Length == 1)
{
t = t.Substring(0, match.Groups[0].Index) +
PinyinToneMark[tone][PinyinToneMark[0].IndexOf(match.Groups[0].Value[0])]
+ t.Substring(match.Groups[0].Index + match.Groups[0].Length);
}
else
{
if (t.Contains("a"))
{
t = t.Replace("a", PinyinToneMark[tone][0].ToString());
}
else if (t.Contains("o"))
{
t = t.Replace("o", PinyinToneMark[tone][1].ToString());
}
else if (t.Contains("e"))
{
t = t.Replace("e", PinyinToneMark[tone][2].ToString());
}
else if (t.Contains("ui"))
{
t = t.Replace("i", PinyinToneMark[tone][3].ToString());
}
else if (t.Contains("iu"))
{
t = t.Replace("u", PinyinToneMark[tone][4].ToString());
}
else
{
t += "!";
}
}
}
}
accented += t;
t = "";
}
}
accented += t + " ";
}
accented = accented.TrimEnd();
return accented;
}
I've used Microsoft Visual Studio International Pack.
This is 1.0 version. and Feature Pack 2.0.
Hope help you!
I think this line
t = t.Substring(0, t.Length - 2) + "\u00fc";
Should be this instead
t = t.Substring(0, t.Length - 1) + "\u00fc";

Categories

Resources