Grouping multiple conditions in IF statements C# - c#

I'm writing a program that needs to perform a search as one of the required functions. The user should be able to use any number of fields, ranging from none to all of them (total of 7). So far I've had success grouping each case of data input within an if statement like so:
List<TypeClass> myList = new List<TypeClass>
foreach TypeClass currentItem in myList
{
if (data1 == currentItem.GetData1() || data1 == "Do Not Search" && (data2 == currentItem.GetData2() || data2 == "Do Not Search") && (data3...)
{
//Stuff
}
}
If you notice, I grouped each data field within brackets, so the statement can only be satisfied if each of the entered data is either the needed condition, or an 'empty field'. However, I can't group the very first portion of the statement as I do with the other data2,3,4... Instead the statement always gets evaluated to true even if there are other search fields that do not satisfy the conditions of the statement. If I use additional brackets the program completely ignores the if statement and treats it as if none of the cases match at all.
So if I write it like this:
if ((data1 == currentIten.GetData1 || data1 == "Do Not Search") && (data2...)
Nothing gets checked and the statement is ignored. Is this normal? Are there any better/more efficient ways of dealing with optional search field selection?
EDIT: Sorry for the typo, each GetDataX is an accessor and I forgot to write the parentheses ()

You could do it like this for an or condition
List<string> mylist = new List<string>();
string data1 = "test1";
string data2 = "test2";
string data3 = "test3";
string data4 = "test4";
foreach (string s in mylist)
{
bool found = false;
if(data1.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
if (data2.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
if (data3.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
if (data4.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
}
Or like this for an and condition
List<string> mylist = new List<string>();
string data1 = "test1";
string data2 = "test2";
string data3 = "test3";
string data4 = "test4";
foreach (string s in mylist)
{
bool found = false;
bool notfound = false;
if(data1.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
else
{
notfound = true;
}
if (data2.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
else
{
notfound = true;
}
if (data3.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
else
{
notfound = true;
}
if (data4.Equals(s) || data1.Equals("Do not Search"))
{
found = true;
}
else
{
notfound = true;
}
// Force all to match
if (notfound)
return null;
}
My Preference would be something like this though where you can leverage search functions to do what you need to.....
List<string> mylist = new List<string>();
List<string> mysearches = new List<string>();
string data1 = "test1";
string data2 = "test2";
string data3 = "test3";
string data4 = "test4";
if(data1 != "Do not Search")
mysearches.Add(data1);
if (data2 != "Do not Search")
mysearches.Add(data2);
if (data3 != "Do not Search")
mysearches.Add(data3);
if (data4 != "Do not Search")
mysearches.Add(data4);
bool found = false;
bool andconditionmatch = true;
foreach (string s in mylist)
{
if (mysearches.Contains(s))
{
found = true;
}
else
{
andconditionmatch = false;
}
}

Put all the possibilities in hashset .
Hashset with all possibilities.
foreach(item in selectedItems) //you may not need this if you dont have to perform action forall selected items.
{
if (Hashset contains item)
//do stuff.
}

I would move the matching inside the class and instead of dealing with 7 separate possible values to match, make them one class instance called criteria. See sample code below:
public enum States
{
None,
Tenesee,
Georgia,
Colorado,
Florida
}
class Item
{
public States State { get; set; }
public string Name { get; set; }
public int ID { get; set; }
public bool IsMatch(Item criteria)
{
bool match = true;
if (criteria.State != States.None) match &= criteria.State == State;
if (!string.IsNullOrEmpty(criteria.Name)) match &= criteria.Name.Equals(Name);
if (criteria.ID > 0) match &= criteria.ID == ID;
return match;
}
public override string ToString()
{
return string.Format("ID={0}, Name={1}, State={2}", ID.ToString(), Name, State.ToString());
}
}
class Program
{
static void Main(string[] args)
{
List<Item> list = new List<Item>();
list.Add(new Item() { ID = 10016, Name = "Julia", State = States.Georgia });
list.Add(new Item() { ID = 10017, Name = "Scott", State = States.Colorado });
list.Add(new Item() { ID = 10018, Name = "Samantha", State = States.Tenesee });
list.Add(new Item() { ID = 10019, Name = "Julia", State = States.Florida });
Item criteria = new Item()
{
State = States.Tenesee,
ID = 10018
};
List<Item> selection = list.FindAll((item) => item.IsMatch(criteria));
foreach (var item in selection)
{
Console.WriteLine("{0}", item);
}
}
}
With the result
ID=10018, Name=Samantha, State=Tenesee
So you build a criteria instance Item and compare for a match if a property is well defined. The loop through all the items and select the ones that match the criteria. Obviously you have to extend .IsMatch() for all 7 properties.

Related

Use foreach to loop through list (or array) as sequence of pairs

I'm creating a simple program that reads username and password from Customers.txt file and verifies if it's correct. Customer.txt is formatted to have sequence of the username then password separated by commas (ignore safety concerns for the exercise):
JohnDoe,1234,JaneDoe,5678,...
Is it possible to create a foreach loop to iterate through the strArray[] and check pairs {strArray[0], strArray[1]} then {strArray[2],strArray[3]} and so on to see if user put the right credentials?
private void enter_click_Click(object sender, RoutedEventArgs e)
{
StreamReader reader1 = new StreamReader("Customers.txt");
string text = reader1.ReadToEnd();
reader1.Close();
string[] Strarray = text.Split(',');
StreamReader reader2 = new StreamReader("Admin.txt");
string text2 = reader2.ReadToEnd();
reader2.Close();
string[] AdminArray = text2.Split(',');
if (username_txt.Text == AdminArray[0] && passwordBox1.Password == AdminArray[1])
{
AdminPage admin = new AdminPage();
admin.Activate();
admin.Show();
method.CheckDate();
return;
}
if (username_txt.Text == Strarray[0] && passwordBox1.Password == Strarray[1])
{
ATM_Screen atm = new ATM_Screen();
atm.Activate();
atm.Show();
method.CheckDate();
return;
}
Yes, you can do this:
var usernames = Strarray.Where((s, i) => { return i % 2 == 0; });
var passwords = Strarray.Where((s, i) => { return i % 2 != 0; });
var userPasswords = usernames.Zip(passwords, (l, r) => new { username = l, password = r });
foreach(var userPassword in userPasswords) {
if (userPassword.username == "rob" && userPassword.password == "robspassword") {
}
}
Edit based on comment:
You can do this for multiple valid credentials:
var allowedCredentials = new List<Tuple<String, String>> {
new Tuple<String, String>("Rob", "Robspassword"),
new Tuple<String, String> ("SomeoneElse", "SomeoneElsespassword"
};
var inputCredentials = new List<string> { "Rob","Robspassword","Rob","Notrobspassword" };
var usernames = inputCredentials.Where((s, i) => { return i % 2 == 0; });
var passwords = inputCredentials.Where((s, i) => { return i % 2 != 0; });
var userPasswords = usernames.Zip(passwords, (l, r) => new { username = l, password = r });
foreach(var userPassword in userPasswords) {
if (allowedCredentials.Any(ac => ac.Item1 == userPassword.username
&& ac.Item2 == userPassword.password)
{
//Valid
}
}
Using foreach is kind of hard to get pairs of elements from sequence:
you can iterate through sequence normally and remember first element on the odd iterations, perform operation on every even iteration
you can convert sequence into pairs first using LINQ and indexing or Zip even and odd half.
Collecting pairs approach:
string name;
bool even = false;
foreach(var text in items)
{
if (even)
{
var password = item;
// check name, password here
}
else
{
name = text;
}
even = !even;
}
Zip-based approach
foreach(var pair in items
.Where((v,id)=>id % 2 == 1) // odd - names
.Zip(items.Where((v,id)=>id % 2 == 0), // even - passwords
(name,password)=> new { Name = name, Password = password}))
{
// check pair.Name, pair.Password
}
Note: It would be much easier to use regular for loop with increment of 2.

Updating nested list values with Linq?

I am trying to update a nested list in C# which looks like this
List<Users>
- UserType
- List<UserComponents>
- - UserComponentKey
- - Count
Here's a written example:
List of users:
UserType = 1
UserComponents
- UserComponentKey = XYZ
- Count = 3
UserType = 2
UserComponents
- UserComponentKey = XYZ
- Count = 7
I need to update UserComponentKey XYZ for UserType 2 only, currently my updates are broken and updates XYZ for all user types. Here is my current methods which do not work as they update the UserComponent count value for ALL usertypes which contain the specified component key, and not the specific usertype I am targeting.
CLASSES:
public class Users
{
public string UserType { get; set; }
public List<UserComponent> UserComponents { get; set; }
}
public class UserComponent
{
public string UserComponentKey { get; set; }
public int Count { get; set; }
}
METHOD 1:
Users.Where(us => us.UserType == "2")
.First().UserComponents
.Where(uc => uc.UserComponentKey == "XYZ")
.First().Count = value;
METHOD 2:
if(users.UserType == "2")
{
foreach(var component in users.UserComponents)
{
switch(component.UserComponentKey)
{
case "XYZ":
component.Count = value;
break;
}
}
}
CODE GENERATING LIST (similar to):
List UserComponents = new List();
if (Item.UserAddOn != null)
{
for (var i = 0; i < Item.UserAddOn.First().Count; i++)
{
UserComponents.Add(new UserComponent
{
UserComponentKey = Item.UserAddOn[i].ComponentKey,
Count = 0
});
}
}
if (Item.User != null)
{
for (var i = 0; i < Item.User.First().Count; i++)
{
Users.Add(new User()
{
UserType = Item.User[i].ComponentKey,
Count = 0,
UsersComponents = UserComponents
});
}
}
I have stripped out actual values etc, but hopefully someone can point me in the right direction here.
Thanks!
I'm missing information to write a snippet you can use so I will simply explain it. An object variable is in reality a reference (a pointer, if you are familiar with C++/C) to the location where the object reside. When you add an object to a list, you add it's location. If you add this object to multiple list, you give the same location and therefor, editing one of them will edit all of them.
var uc1 = new UserComponent { Count = 1 };
var uc2 = new UserComponent { Count = 2 };
var uc3 = new UserComponent { Count = 2 };
var u1 = new User();
var u2 = new User();
u1.UserComponents.Add(uc1);
u1.UserComponents.Add(uc2);
u2.UserComponents.Add(uc1);
u2.UserComponents.Add(uc3);
Console.Write(u1.UserComponents[0].Count); //Outputs 1
Console.Write(u1.UserComponents[1].Count); //Outputs 2
Console.Write(u2.UserComponents[0].Count); //Outputs 1
Console.Write(u2.UserComponents[1].Count); //Outputs 2
u2.UserComponents[0].Count = 5;
u2.UserComponents[1].Count = 6;
Console.Write(u1.UserComponents[0].Count); //Outputs 5
Console.Write(u1.UserComponents[1].Count); //Outputs 6
Console.Write(u2.UserComponents[0].Count); //Outputs 5
Console.Write(u2.UserComponents[1].Count); //Outputs 2
So your code to change values is fine, but when you build up your list, you need to create distinct UserComponents if they are not linked together.
Your first call to First() is wrong. Try it like this:
Users.Where((us) => us.UserType == "2")
.Select((us) => us.UserComponents)
.Where((uc) => uc.UserComponentKey == "XYZ")
.First()
.Count = value;
Suggestion: Why don't you make UserType an int?
May be it helps:
List<Users> _users = new List<Users>();
_users.Add(new Users() { UserType = "1", UserComponents = new List<UserComponent>() { new UserComponent() { Count = 0, UserComponentKey = "XYZ" } } });
_users.Add(new Users() { UserType = "2", UserComponents = new List<UserComponent>() { new UserComponent() { Count = 2, UserComponentKey = "XYZ" } } });
_users.Add(new Users() { UserType = "3", UserComponents = new List<UserComponent>() { new UserComponent() { Count = 5, UserComponentKey = "XYZ" } } });
_users.Where(us => us.UserType == "2").First().UserComponents.Where(uc => uc.UserComponentKey == "XYZ").First().Count = 356;
foreach (Users us in _users)
{
Console.WriteLine("UserType: " + us.UserType);
foreach (UserComponent uc in us.UserComponents)
{
Console.WriteLine("Key: {0} Value: {1}", uc.UserComponentKey, uc.Count);
}
}

how to Add the standard Analyzer in sitecore 6.5 so that stop word is not ignored

I have the following code when iam searching it searches with all the key words for 1.example : London
2.example : London Bridge
but when i search by
example3 : in London Bridge
it does not return any results. and also my scores are not sorted. here my am making search only in title and trying to sort by scores (highest to lowest)
following is my code to making search only in title and trying to sort by scores (highest to lowest)
public SearchResultCollection Search(string searchString, string ProgramCampusStage, out Hits hitScores)
{
var searchIndex=Sitecore.Search.SearchManager.GetIndex(SearchIndexName);
using (IndexSearchContext context = searchIndex.CreateSearchContext())
{
// get the search term
string searchterm = searchString.ToLower().Trim();
PhraseQuery completeQuery = new PhraseQuery();
completeQuery.SetSlop(4);
foreach (var s in searchterm.Split(' '))
{
completeQuery.Add(new Term("title", s));
}
hitScores = context.Searcher.Search(completeQuery, new Sort(new SortField[1] { SortField.FIELD_SCORE }));
SearchHits hits = new SearchHits(hitScores);
var results = hits.FetchResults(0, Int32.MaxValue);
foreach (var result in results)
{
try
{
Item item = result.GetObject<Item>();
bool isAuthorized = UserUtility.IsUserAuthorized(item, ProgramCampusStage);
if (isAuthorized)
{
if (item != null)
{
string categoryName = GetCategoryName(item);
if (item.Language.Name != Context.Language.Name || categoryName == string.Empty)
{
continue;
}
results.AddResultToCategory(result, categoryName);
}
else
{
results.AddResultToCategory(result, OtherCategory);
}
}
}
catch
{
continue;
}
}
return _searchResults = results;
}
}
}
Instead of adding the stop words as terms in your index (which could cause you other headaches like 'too many clauses' exceptions), you could try filtering out the stop words when you construct your query:
foreach (var s in searchterm.Split(' '))
{
if (!Lucene.Net.Analysis.Standard.StandardAnalyzer.STOP_WORDS_SET.Contains(s))
{
completeQuery.Add(new Term("title", s));
}
}

C# (String.StartsWith && !String.EndsWith && !String.Contains) using a List

I am a newbie in C#, and I am having problems.
I have 2 List, 2 strings and a getCombinations(string) method that
returns all combinations of a string as List;
How do i validate if a subjectStrings element does not
StartWith && !EndsWith && !Contains (or !StartWith && !EndsWith && Contains, etc.)
for every combinations of startswithString, endswithString and containsString?
Here is my code in StartWith && !EndsWith
(if you want to see it running: http://ideone.com/y8JZkK)
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
List<string> validatedStrings = new List<string>();
List<string> subjectStrings = new List<string>()
{
"con", "cot", "eon", "net", "not", "one", "ten", "toe", "ton",
"cent", "cone", "conn", "cote", "neon", "none", "note", "once", "tone",
"cento", "conte", "nonce", "nonet", "oncet", "tenon", "tonne",
"nocent","concent", "connect"
}; //got a more longer wordlist
string startswithString = "co";
string endswithString = "et";
foreach(var z in subjectStrings)
{
bool valid = false;
foreach(var a in getCombinations(startswithString))
{
foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
if(valid)
{
break;
}
}
if(valid)
{
validatedStrings.Add(z);
}
}
foreach(var a in validatedStrings)
{
Console.WriteLine(a);
}
Console.WriteLine("\nDone");
}
static List<string> getCombinations(string s)
{
//Code that calculates combinations
return Permutations.Permutate(s);
}
}
public class Permutations
{
private static List<List<string>> allCombinations;
private static void CalculateCombinations(string word, List<string> temp)
{
if (temp.Count == word.Length)
{
List<string> clone = temp.ToList();
if (clone.Distinct().Count() == clone.Count)
{
allCombinations.Add(clone);
}
return;
}
for (int i = 0; i < word.Length; i++)
{
temp.Add(word[i].ToString());
CalculateCombinations(word, temp);
temp.RemoveAt(temp.Count - 1);
}
}
public static List<string> Permutate(string str)
{
allCombinations = new List<List<string>>();
CalculateCombinations(str, new List<string>());
List<string> combinations = new List<string>();
foreach(var a in allCombinations)
{
string c = "";
foreach(var b in a)
{
c+=b;
}
combinations.Add(c);
}
return combinations;
}
}
Output:
con
cot
cone
conn
cote <<<
conte <<<
concent
connect
Done
if(z.StartsWith(a) && !z.EndsWith(b))
var b can be "et" and "te", but cote and conte endswith "te",
why it is still added in my validated strings?
Thanks in advance.
z.StartsWith(a) && !z.EndsWith(b)
check below combination
z ="cote"
a ="co"
b ="te"
so z start with "co" and z not end with "te", your condition pass and cote will add to list
i would try as below
var sw =getCombinations(startswithString);
var ew = getCombinations(endswithString);
var result = subjectStrings.Where(z=>
sw.Any(x=>z.StartsWith(x) &&
!ew.Any(y=>z.EndsWith(y))))
.ToList();
DEMO
output :
con
cot
cone
conn
concent
connect
foreach(var b in getCombinations(endswithString))
{
if(z.StartsWith(a) && !z.EndsWith(b))
{
valid = true;
break;
}
}
here you are setting valid to true as soon as there is match for !z.EndsWith(b) and you are not traversing the whole list of permutations available.
since "cote" doesn't end with "et" it is a match and valid is set to true and the code breaks.
So that's why "cote" is added to your list of valid strings. So is the case with "conte".
What you want to do is :
List<string> startsWithCombination = getCombinations("co");
List<string> endsWithCombination = getCombinations("et");
foreach (var z in subjectStrings)
{
bool isStartMatchFound = startsWithCombination.Any(b => z.StartsWith(b));
if (isStartMatchFound)
{
bool isEndMatchFound = endsWithCombination.Any(b => z.EndsWith(b));
if (!isEndMatchFound)
{
validatedStrings.Add(z);
}
}
}

How add only new city?

I have CreateDiscountViewByUser discountViewByUser it contains a list of cities that are chosen by the user, but they may already be those cities that have been added.
List<DiscountCity> discountCities = (from city in db.DiscountCities
where city.DiscountId == discountViewByUser.Id
select city).ToList();
for (int y = 0; y < discountCities.Count(); y++)
{
var dc = discountCities[y];
bool flag = false;
for (int i = 0; i < discountViewByUser.DiscountCitys.Length; i++)
{
if (dc.CityId == discountViewByUser.DiscountCitys[i])
{
flag = true;
discountCities.Remove(dc);
y--;
}
}
if (!flag)
{
db.DiscountCities.DeleteObject(dc);
}
}
foreach (var dc in discountCities)
{
DiscountCity discountCity = new DiscountCity
{Id = Guid.NewGuid(),
CityId = dc.CityId,
DiscountId = main.Id};
db.DiscountCities.AddObject(discountCity);
}
how to add only the new city?
My code does not work = (
UPDATE:
discountViewByUser.DiscountCitys type int[].
db.DiscountCities table: Id DiscountId CityId.
example:
in database: Odessa, Kiev
user set: Odessa, Moscow.
I need delete Kiev and add moscow how do this?
What I recommend is adding all the items and then removing duplicates.
// Where uniqueList is a List<T> of unique items:
uniqueList.AddRange(valuesToAdd);
uniqueList = uniqueList.Distinct(new CityEqualityComparer()).ToList();
// Sorry, I don't know how this would fit into your code
Since you are comparing cities by their CityId's, you will probably need to use a custom IEqualityComparer to determine which cities are duplicates.
Here is an example of such a class:
class CityEqualityComparer : IEqualityComparer<City>
{
public bool Equals(City arg1, City arg2)
{
return arg1.CityId == arg2.CityId;
}
public int GetHashCode(City arg)
{
return arg.CityId;
}
}
This question may also be of some help.
I suggest you do this in 2 steps.
1) Find the cities to be deleted
var deleteCities = db.DiscountCities.Where(c => c.DiscountId == discountViewByUser.Id
&& !discountViewByUser.DiscountCitys.Contains(c.CityId));
foreach(deleteCity in deleteCities)
{
db.DiscountCities.DeleteObject(deleteCity);
}
2) Find cityId's to be inserted
var insertCities = discountViewByUser.DiscountCitys.Except(
db.DiscountCities.Where(c => c.DiscountId == discountViewByUser.Id)
.Select(c => c.CityId));
foreach(var insertCity in insertCities)
{
DiscountCity discountCity = new DiscountCity
{Id = Guid.NewGuid(), CityId = insertCity, DiscountId = discountViewByUser.Id};
db.DiscountCities.AddObject(discountCity);
}

Categories