Need Help - Checking char values throughout the alphabet

J

Jack Addington

I want to scroll through the alphabet in order to scroll some data to the
closest name that starts with a letter. If the user hits the H button then
it should scroll to the letter closest to H. If no one exists with H, then
go to I, etc. If its near the end, say 'V', and the last person is a 'T'
then it should work its way back up the alphabet. I was trying to loop as
if the Char's were ints but I am having problems

I have buttons with A .. Z that have the letter in the Tag field.

char key = button.Tag.ToString().ToCharArray(1,1)[0]; // get the letter
to search for ...

// work our way down the alphabet
while (row == 0 && (int)key <= (int)'Z') {
row = list.find (firstletter = key )
(int)key++;
}

// if we didn't find something at least lower than the button pressed
then try going up the alphabet
if (row==0) {
key = (char)(int)button.Tag.ToString().ToCharArray(1,1)[0] - 1;
// work our way up the alphabet
while (row == 0 && (int)key >= (int)"A") {
row = this.dwPatientList.FindRow("left(sorted_name,1)='" + key
+ "'",row,dwPatientList.RowCount);
(int)key--;
}
}

Scroll to row
 
J

Jeff Louie

Jack... OFF THE TOP OF MY POINTED HEAD here is some code to find partial
matches in an array list. You could modify and TEST this code to suit
your needs.

////////////// UNTESTED CODE ///////////////

using System;
using System.Collections;

namespace TestBinarySearch
{
/// <summary>
/// Summary description for Class1.
/// UNTESTED CODE
/// </summary>
///
class MyCaseInsensitiveCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
return String.Compare((string)x,(string)y,true);
}
}
class MyCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
int length= ((string)y).Length;
if (((string)x).Length < length) return -1;
return String.Compare((string)x,0,(string)y,0,length,true);
}
}
class Class1
{
private ArrayList al= new ArrayList();

// ASSERT find not null
public void FindIt(string find)
{
// Do BINARY_SEARCH to find any partial match
al.Sort(new MyCaseInsensitiveCompare());
int index= al.BinarySearch(find, new MyCompare());
System.Console.WriteLine("Find: "+find);
if (index < 0) System.Console.WriteLine("No Match.");
else
//got at least one match for criteria find&
{
System.Console.WriteLine("Output");

// now do LINEAR_SEARCH for other matches
int firstIndex= index;
int lastIndex= index;
MyCompare mc= new MyCompare();
for (int i=index-1; i>=0 && (mc.Compare(al,find)==0) ; i--)
{
firstIndex= i;
}
for (int i=index+1; (i<al.Count) && (mc.Compare(al,find)==0);
i++)
{
lastIndex= i;
}
for (int i=firstIndex;i<=lastIndex;i++)
{
System.Console.WriteLine(al);
}
}
}
//ASSERT al not null
public Class1(ArrayList al)
{
this.al= al;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
ArrayList al= new ArrayList();
al.Add("Louie,Jeff");
al.Add("Smith,Ann");
al.Add("Smith,J");
al.Add("Smith,Dick,");
al.Add("Smith,Peter,");
al.Add("Smith,Jan");
al.Add("Smith,Tom");
al.Add("Smith,Harry");
al.Add("Smith,Joe");
al.Add("Smith,Joe");
al.Add("Smith,John");
Class1 c1= new Class1(al);
c1.FindIt("SMITH,JO");
System.Console.ReadLine();
}
}
}

Regards,
Jeff
I want to scroll through the alphabet in order to scroll some data to
the closest name that starts with a letter.<
 
J

Jeff Louie

Second try... I just wrote this off the top of my pointed head. This
code looks for a partial match in an array list. You could try to modify
it.

////////// UNTESTED CODE //////////////////
using System;
using System.Collections;

namespace TestBinarySearch
{
/// <summary>
/// Summary description for Class1.
/// UNTESTED CODE
/// </summary>
///
class MyCaseInsensitiveCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
return String.Compare((string)x,(string)y,true);
}
}
class MyCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
int length= ((string)y).Length;
if (((string)x).Length < length) return -1;
return String.Compare((string)x,0,(string)y,0,length,true);
}
}
class Class1
{
private ArrayList al= new ArrayList();

// ASSERT find not null
public void FindIt(string find)
{
// Do BINARY_SEARCH to find any partial match
al.Sort(new MyCaseInsensitiveCompare());
int index= al.BinarySearch(find, new MyCompare());
System.Console.WriteLine("Find: "+find);
if (index < 0) System.Console.WriteLine("No Match.");
else
//got at least one match for criteria find&
{
System.Console.WriteLine("Output");

// now do LINEAR_SEARCH for other matches
int firstIndex= index;
int lastIndex= index;
MyCompare mc= new MyCompare();
for (int i=index-1; i>=0 && (mc.Compare(al,find)==0) ; i--)
{
firstIndex= i;
}
for (int i=index+1; (i<al.Count) && (mc.Compare(al,find)==0);
i++)
{
lastIndex= i;
}
for (int i=firstIndex;i<=lastIndex;i++)
{
System.Console.WriteLine(al);
}
}
}
//ASSERT al not null
public Class1(ArrayList al)
{
this.al= al;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
ArrayList al= new ArrayList();
al.Add("Louie,Jeff");
al.Add("Smith,Ann");
al.Add("Smith,J");
al.Add("Smith,Dick,");
al.Add("Smith,Peter,");
al.Add("Smith,Jan");
al.Add("Smith,Tom");
al.Add("Smith,Harry");
al.Add("Smith,Joe");
al.Add("Smith,Joe");
al.Add("Smith,John");
Class1 c1= new Class1(al);
c1.FindIt("SMITH,JOHN");
System.Console.ReadLine();
}
}
}

Regards,
Jeff
I want to scroll through the alphabet in order to scroll some data to
the closest name that starts with a letter.<
 
J

Jack Addington

Jeff,

Thanks for the code... It makes sense but kinda missed what I needed help
with, I think it did more than what I need to do.

I am tryingto simulate the contacts in outlook with the list of letters down
the side. I have a set of data (alphabeticly sorted names) and I want to
try and get the closest hit based on the first letter of the last name. My
big problem was how to increment my search character. If I can't find 'W',
then try 'X' etc. If I hit 'Z' with no luck then start looking up for 'V',
then 'U'.

I have my char from the button.Tag.ToString().ToArray()[0]. I was trying to
convert it to an int, increment it, then try my search again. I was trying
to be too fancy with the shorthand ie (int)key++ etc but after a while my
code just became confusing. I was looking for a simple approach via a
method I wasn't familiar with or something.

thx

jack


Jeff Louie said:
Second try... I just wrote this off the top of my pointed head. This
code looks for a partial match in an array list. You could try to modify
it.

////////// UNTESTED CODE //////////////////
using System;
using System.Collections;

namespace TestBinarySearch
{
/// <summary>
/// Summary description for Class1.
/// UNTESTED CODE
/// </summary>
///
class MyCaseInsensitiveCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
return String.Compare((string)x,(string)y,true);
}
}
class MyCompare : IComparer
{
// ASSERT x, y are strings not null
// Case insensitive
public int Compare(object x, object y)
{
int length= ((string)y).Length;
if (((string)x).Length < length) return -1;
return String.Compare((string)x,0,(string)y,0,length,true);
}
}
class Class1
{
private ArrayList al= new ArrayList();

// ASSERT find not null
public void FindIt(string find)
{
// Do BINARY_SEARCH to find any partial match
al.Sort(new MyCaseInsensitiveCompare());
int index= al.BinarySearch(find, new MyCompare());
System.Console.WriteLine("Find: "+find);
if (index < 0) System.Console.WriteLine("No Match.");
else
//got at least one match for criteria find&
{
System.Console.WriteLine("Output");

// now do LINEAR_SEARCH for other matches
int firstIndex= index;
int lastIndex= index;
MyCompare mc= new MyCompare();
for (int i=index-1; i>=0 && (mc.Compare(al,find)==0) ; i--)
{
firstIndex= i;
}
for (int i=index+1; (i<al.Count) && (mc.Compare(al,find)==0);
i++)
{
lastIndex= i;
}
for (int i=firstIndex;i<=lastIndex;i++)
{
System.Console.WriteLine(al);
}
}
}
//ASSERT al not null
public Class1(ArrayList al)
{
this.al= al;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
ArrayList al= new ArrayList();
al.Add("Louie,Jeff");
al.Add("Smith,Ann");
al.Add("Smith,J");
al.Add("Smith,Dick,");
al.Add("Smith,Peter,");
al.Add("Smith,Jan");
al.Add("Smith,Tom");
al.Add("Smith,Harry");
al.Add("Smith,Joe");
al.Add("Smith,Joe");
al.Add("Smith,John");
Class1 c1= new Class1(al);
c1.FindIt("SMITH,JOHN");
System.Console.ReadLine();
}
}
}

Regards,
Jeff
I want to scroll through the alphabet in order to scroll some data to
the closest name that starts with a letter.<
 
J

James Curran

You're rather vague on what your list looks up (you use "list.find" in
one spot and "this.dwPatientList.FindRow" in another), but it seems the
find/FindRow is inadequate for what you want to do, so don't use it.

char key = button.Tag.ToString()[0];
// if you store the letter in the button's Text property, you can make
that even simpler:
// char key = button.Text[0];
MyRow found_row = null;

foreach (MyRow row in dwPatientList)
{
found_row = row;
if (row.sorted_name[0] >= key)
break;
}

The loop will exit when the first letter of found_row is equal to or
greater that key (which is what you what) -- or -- it will exit at the end
of the list, with found_row set to the last item (i.e., the first one BEFORE
key)
--
Truth,
James Curran
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
(note new day job!)
 
J

Jeff Louie

Jack.... I think your question has been answered. A linear search may
work on
a small data list, but is going to be very inefficient on a list of any
considerable size. A sorted list begs to be searched with a binary
search, not
a linear search. The code I posted attempts to provide a common
functionality, finding the set of rows with a partial match to a key in
a sorted
list. If you anticipate the list may grow significantly, then I would
seriously
consider a search algorithm other than a linear search. The most
efficient may
be to write your own binary_search that leaves you at the nearest match
if no
match is found. If your data is best described as buckets of data
organized by
letter, you could break up the data into buckets by letter (say an array
list for
each letter in the alphabet) and then go to the bucket that needs to be
searched. If the bucket is empty, it would be trivial to iterate to the
first
bucket of data that is not empty.

Regards,
Jeff
I am tryingto simulate the contacts in outlook with the list of letters
down
the side. I have a set of data (alphabeticly sorted names) and I want to
try and get the closest hit based on the first letter of the last name<
 
J

Jack Addington

You are right... I wasn't very clear

I'm not writing the find routine... the dwXXX object does it already. I was
just trying to be generic when I put list.find at the top and forgot to do
it at the bottom.

What I was doing was trying to do was to iterate through the search term and
let the dwXXX object do the searching. My problem was coming up with a
clean and efficient syntax (not algorithm) as I am new to c# that let me
cleanly loop through the letters.


James Curran said:
You're rather vague on what your list looks up (you use "list.find" in
one spot and "this.dwPatientList.FindRow" in another), but it seems the
find/FindRow is inadequate for what you want to do, so don't use it.

char key = button.Tag.ToString()[0];
// if you store the letter in the button's Text property, you can make
that even simpler:
// char key = button.Text[0];
MyRow found_row = null;

foreach (MyRow row in dwPatientList)
{
found_row = row;
if (row.sorted_name[0] >= key)
break;
}

The loop will exit when the first letter of found_row is equal to or
greater that key (which is what you what) -- or -- it will exit at the end
of the list, with found_row set to the last item (i.e., the first one
BEFORE
key)
--
Truth,
James Curran
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
(note new day job!)

Jack Addington said:
I want to scroll through the alphabet in order to scroll some data to the
closest name that starts with a letter. If the user hits the H button then
it should scroll to the letter closest to H. If no one exists with H, then
go to I, etc. If its near the end, say 'V', and the last person is a 'T'
then it should work its way back up the alphabet. I was trying to loop
as
if the Char's were ints but I am having problems

I have buttons with A .. Z that have the letter in the Tag field.

char key = button.Tag.ToString().ToCharArray(1,1)[0]; // get the
letter
to search for ...

// work our way down the alphabet
while (row == 0 && (int)key <= (int)'Z') {
row = list.find (firstletter = key )
(int)key++;
}

// if we didn't find something at least lower than the button pressed
then try going up the alphabet
if (row==0) {
key = (char)(int)button.Tag.ToString().ToCharArray(1,1)[0] - 1;
// work our way up the alphabet
while (row == 0 && (int)key >= (int)"A") {
row = this.dwPatientList.FindRow("left(sorted_name,1)='" + key
+ "'",row,dwPatientList.RowCount);
(int)key--;
}
}

Scroll to row
 
J

Jack Addington

Jeff,

Sorry I'm not that clear. I'm not looking for a search/sort routine. My
object containing the data already has a find routine. Thats why I
generically called it list.Sort and accidently left the exact code
dwPatientList.Find(...) in the lower section. I'm very sorry if you feel
I've wasted your time. Although I did spend a long time reading over your
earlier post.

What I was looking for was help with the c# syntax to 'neatly and
efficiently' increase/decrease the alphabetical character if the find was
unsuccessful. The data object I am using has a very very fast search so I
wasn't worried about not calling it over and over but with a different first
argument. As my list grows there is far more chance that I will pick up
each letter of the alphabet as a last name so the chance of doing more than
one search will diminish.

thanks so much for you time.
 
J

Jeff Louie

Sorry I'm not that clear.<
Not a problem.
What I was looking for was help with the c# syntax to 'neatly and
efficiently' increase/decrease the alphabetical character if the find
was unsuccessful.<
OK Have fun.
////////////// SOME CODE ///////////////////////////

using System;

namespace TestASCII
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
[STAThread]
static void Main(string[] args)
{
string myString= "ABCXYabcxyz";
foreach (char ch in myString)
{
System.Console.Write(ch);
System.Console.WriteLine(Class1.GetNextLetter(ch));
}
// USAGE
try
{
System.Console.WriteLine(Class1.GetNextLetter(myString[0]));
System.Console.WriteLine(Class1.GetNextLetter('1'));
}
catch(Exception e)
{
System.Console.WriteLine(e);
}
System.Console.ReadLine();
}
//ASSERT inChar is a letter
public static char GetNextLetter(char inChar)
{
if ((inChar>64) && (inChar<91)) // UPPER CASE
{
if (inChar == 90) {return (char)65;}
else return (++inChar);
}
else if ((inChar>96) && (inChar<123)) //lower case
{
if (inChar == 122) {return (char)97;}
else return (++inChar);
}
else throw new ArgumentOutOfRangeException();
}
}
}

Regards,
Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top