Using lambda expression to get values in an array - c#

Alright, here's the deal. I am doing a data conversion where I'm taking data from two databases and putting it into another. I'm adding a list of contacts, and then I'm adding a list of communication records. In order to simplify the process, I made a small array of all of the communication records with the household address of the contacts. Now I'm trying to use a lambda expression to sort out email addresses from the array, but I'm having a problem. The code so far is as follows:
DataRow[] Comms = dtComms.Select("household_id = " + previousID);
if (Comms.Where(x => x.Field<string>("communication_type") == "Home Phone").Count() > 0)
{
string HomePhone = rNDigits.Replace(Comms[0].Field<string>("communication_value").ToString().Trim(), "");
if (HomePhone.Length > 6)
oAddress._Phone = HomePhone;
}
if (Comms.Where(x => x.Field<string>("communication_type") == "Email").Count() > 0)
{
string FamilyEmail = rNDigits.Replace(Comms[0].Field<string>("communication_value").ToString().Trim(), "");
if (FamilyEmail.Contains('#') && FamilyEmail.Contains('.'))
oAddress._FamilyEmail = FamilyEmail;
}
The problem is that obviously, this always will return the first value in the array, which might not always be the one that I want. How can I change the code so that it selects only the value from the array that matches the entry containing the email? Or, is there a better way to search through values in an array?

I suggesting to use a simple for or foreach loop in this case, LINQ can't modify data only select it.

Related

Check if a second list contains all values of the first

I have the following problem:
I have a Database with a table where I save a String and a Date.
In this table I add an Entry if a certain assignment is printed and when.
On the other hand I have a Database Table from where I get the assignments to do for today.
After inserting the new entry into the Database I select the String with the assignment number and put it into a database,
so I can compare those two lists and check if the list with the printed elements contains all values from the assignments to print today.
How can I achieve this?
I've tried several methods but it always returns false.
The methods I've tried:
if (serial_list_printed.All(x => serial_list.Contains(x)) == true)
{
status = true;
}
else
{
Console.WriteLine("False");
}
2nd Method:
if (serial_list.All(x => serial_list_printed.All(y => y == x)))
{
status = true;
}
else
{
Console.WriteLine("False");
}
How can I check that all the List of Strings with the printed assignment numbers, contains the list of today's assignments?
You can use Except() to get difference between two list and count length of result,
var status = serial_list.Except(serial_list_printed).Any();
if(!status)
Console.WriteLine("False");

c# Object properties is loading from cache

in my win-form application, there is a method that combines some items that have been created previously, when the code is the first time to run, everything is fine, but in second and later runs combined items have the wrong length.
the code reads items from a SQL server using LINQ that has object type named "BetaData"
BetaData has a property named "Length" that is double.
I have another list that processed items is stored in name "PartList" of type "ModifiedPartList".
in method length property changes for some items, but nothing gets stored or saved on SQL.
this is the main method:
private List<ModifiedPartList> CombinePartList(ProgressBar Bar)
{
PartList.Clear();
List<BetaData> PartsinOrder = new List<BetaData>();
foreach (int view in Globals.Views)
{
List<int> OrdersInView = new List<int>();
foreach (Tuple<int, int> tuple in Globals.Orders)
{
if (tuple.Item1 == view)
{
if (!OrdersInView.Contains(tuple.Item2))
OrdersInView.Add(tuple.Item2);
}
}
if(OrdersInView.Count>0)
{
OrdersInView.Sort();
foreach (int order in OrdersInView)
{
//this is the section that problem occurs:
var parts = from BetaData in BetaContext.BetaDatas
where BetaData.ProjectName == Globals.ProjectName &&
BetaData.ProjectCode == Globals.ProjectCode &&
BetaData.ParentItem != Globals.ProjectName + "(" + Globals.ProjectCode + ")" &&
BetaData.View == view &&
BetaData.Order == order
select BetaData;
PartsinOrder.Clear();
PartsinOrder = parts.ToList();
foreach(BetaData part in PartsinOrder)
{
Bar.PerformStep();
}
}
}
PartsinOrder.Clear();
}
return PartList;
}
in the section that i have commented as problem location when the code is running for the second time, optimized length property is loaded to items instead of their original value from SQL. i cannot understand that because each time i read all items from SQL server.
the point is in this stage after that i ran the method for several times and getting the wrong results when i close the program and start it again, on first run results are true.
after selecting from SQL and converting it to list, i review items and their properties in list, and they are all true, but in foreach loop when each part comes into loop their Length property is wrong.
the issue was solved using this article and refreshing context after retrieving data from SQL

How do I modify selected items in asp:listbox for use in a proper string?

Lets say I wanted to create an application for a user to select trouble departments for reporting purposes. The user would go in and select multiple trouble departments from a asp:ListBox and when the user hits send the email would read,
We are having trouble in the following departments: DepartmentA, DepartmentB.
What I have been able to is figure out how to properly loop the items out from the loop, however the last item has a , at the end of the last item. For example instead of reading the proper way as noted above it looks like this:
We are having trouble in the following departments: DepartmentA, DepartmentB,.
Here is my code:
string DeptID = string.Empty;
foreach (ListItem li in lstDSXDepartment.Items)
{
if (li.Selected == true)
{
DeptID += li.Value + ",";
}
}
Response.Write("We are having trouble with the following Departments: " + DeptID + ".");
How do I fix the string so that the comma does not show at the end of list of selections?
You can use string.join. It is much easier.
var ids = lstDSXDepartment.Items
.Cast<ListItem>()
.Where(x=> x.Selected)
.Select(x=> x.Value);
string text = string.Join(",", ids);
Other thought:
If you want to use your original method, you should consider using StringBuilder instead of String because String is immutable.
StringBuilder will significantly improve the performance depending on the number of Items.
Just use a trim function to remove the unwanted comma.
DeptID = DeptID.TrimEnd(',');
Use after the loop, before writing.
Note: The TrimEnd function returns a new copy that is modified of the original string so you have to store it back into your original variable. This is because strings are immutable in C#.

Entity Framework and whole word matching - paging and filtering results

Background:
I am using ASP.NET MVC4, SQL Server 2008 R2, and Entity Framework 5 for a website.
The site accepts a delimited list of keywords to search database content on. It also needs to page the results to the user (currently 100 results per page).
This was going along smoothly until it was requested that the keyword searching is not done with partial matching, but whole word matching.
The problem
Performing the whole word match AFTER I already have the results back means that I might not have query.Pagesize of results to show - which messes up the UI paging. Of the 100 partial matches from SQL Server on the first page, 20 may end being removed with the whole word processing.
I currently am building my query using LINQ and doing a AND search on the keywords like so:
// Start with all the MyItems
var results = UnitOfWork.MyItemRepository.GetAll();
// Loop the keywords to AND them together
foreach(var keyword in query.Keywords)
{
var keywordCopy = keyword;
// Look for a hit on the keyword in the MyItem
results = results.Where(x => x.Title.Contains(keywordCopy));
}
And later on getting the total number of results, paging, and executing the query:
var totalCount = results.Count();
// Page the results
results = results.Skip((query.Page - 1) * query.Pagesize).Take(query.Pagesize);
...
// Finalize the query and execute it
var list = results.ToList();
Because I need to do whole word matching and not partial, I am processing with a regex the keywords and removing non-matches from list.
var keywordsRegexPattern = "^" + string.Concat(query.Keywords.Select(keyword => string.Format(#"(?=.*\b{0}\b)", Regex.Escape(keyword))));
foreach(var item in list.ToList())
{
var searchableData = some combined string of item data
// See if the keywords are whole word matched in the combined content
var isMatch = Regex.IsMatch(searchableData, keywordsRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
// If not a match, remove the item from the results
if(!isMatch)
{
list.Remove(item);
}
}
// Change list into custom list of paged items for the UI
var pagedResult = new PagedList<MyItem>(list, query.Page, query.Pagesize, totalCount);
return pagedResult;
Question
Does anyone know of a way to do whole word matching with EF and do result paging?
Ideas I've come up with but don't like:
Chunk the results. 100 results back, 20 partial keyword matches removed, go get another 20, repeat. This could result in doing multiple queries when getting all the data at once would have been faster. It also means it would be stealing potential results from the next page which would have to be tracked with some sort of offset.
Get ALL the rows back (no SQL paging), then process and page in C#. This seems bad to get all the results back every time.
Well I see two alternatives (I may miss something easier, but anyway)
Either you use string.Contains(keyword), retrieve all the corresponding datas from db, then filter with exact matching and make paging on the enumerated result (so you probably get "not too much result" from db).
The other way :
foreach(var keyword in query.Keywords)
{
//add space at start or end of keyword for contains
var containsKeyword = string.Format(" {0} ", keyword);
//add space at end only for startsWith
var startsWithKeyword = string.Format("{0} ", keyword);
//add space at start only for endsWith
var endsWithKeyword = string.Format(" {0}", keyword);
// Look for a hit on the keyword in the MyItem
results = results.Where(x => x.Title.Contains(containsKeyword) || x.Title.StartsWith(startsWithKeyword) || x.Title.EndsWith(endsWithKeyword));
}

How to do a search from a list with non-prefix keywords

I am programming a program to search the name from the list and I need to find them even if the keyword is not in front of the names (that's what I mean non-prefix)
e.g. if I my list is the music instruments and I type "guit" to the search textbox.
It should find the names "Guitar, GuitarrĂ³n, Acoustic Guitar, Bass Guitar, ..."
or something like this Longdo Dictionary's search suggestion.
here is my simple and stupid algorithm (that's all I can do)
const int SEARCHROWLIMIT = 30;
private string[] DoSearch(string Input, string[] ListToSearch)
{
List<string> FoundNames = new List<string>();
int max = 0;
bool over = false;
for (int k = 0; !over; k++)
{
foreach (string item in ListToSearch)
{
max = (max > item.Length) ? max : item.Length;
if (k > item.Length) continue;
if (k >= max) { over = true; break; }
if (!Input.Equals("Search")
&& item.Substring(k, item.Length - k).StartsWith(Input, StringComparison.OrdinalIgnoreCase))
{
bool exist = false;
int i = 0;
while (!exist && i < FoundNames.Count)
{
if (item.Equals(FoundNames[i]))
{
exist = true;
break;
}
i++;
}
if (!exist && FoundNames.Count < SEARCHROWLIMIT)
FoundNames.Add(item);
else if (FoundNames.Count >= SEARCHROWLIMIT) over = true;
}
}
}
return FoundNames.ToArray();
}
I think this algorithm is too slow for a large number of names and after several trial-and-error, I decided to add SEARCHROWLIMIT to breaks the operation
And I also think there're some readymade methods that can do that.
And another problem is I need to search music instruments by a category like strings, percussions, ... and by the country of origins. So I need to search them with filter by type and country.
How can I achieve this?
Using LINQ you could write code like this:
var resultSet = products
// filter products by category
.Where(product => product.Category == "strings")
// filter products by origin
.Where(product => product.Origin == "italy")
// filter products whose name contains a word starting with "guit"
.Where(product => (" " + product.Name).Contains(" guit"))
// limit the result set to the first 30 matching products
.Take(30);
If your sets of products is reasonably small, you can use LINQ-to-Objects. Otherwise you should use a database and have a look at LINQ-to-SQL.
One word. Database!
Seriously, if you want to do all these different searches, consider placing your data into a database with a schema that simplifies the categorization issues you are having. Sql Server Express now supports full text search which would be very useful for the kind of search you are trying to perform.
There's a nice blog post here about using FTS with Linq-to-Sql.
static List<string> GetItemsWithWordsStartingWithSubstring(List<string> list, string substring)
{
var query = from str in list
from item in str.Split(' ')
where item.StartsWith(substring, StringComparison.InvariantCultureIgnoreCase)
select str;
return query.ToList();
}
I hope I have read your intiial question properly. This function will return any item from the list that contains a word starting with your substring. More punctuation could be added to the split parameters. Given a list with the following contents:
"abcdef","defabc","def abc","xyz"
A search on "abc" will find "abcdef" and "def abc", but not "defabc".

Categories

Resources