Compare List<string> and enable the required control - c#

I am having two list<string> as follows
listA is having the following values 10,20,30,40 and
listB is having the following values 10,20,30
If listB contains listA elements i would like to enable particular controls if not i would like to disable the Controls
I tried of using two loops as follows
for(int ilist1=0;ilist1<listA.count;ilist1++)
{
for(int ilist2=0;ilist2<listB.count;ilist2++)
{
if(listA[ilist1]==listB[ilist2])
{
//Enable particular control
}
}
}
But i know this is not an appropriate one to do so can any one tell me the best approach to achieve this

What you want to do is to hash the items in the first list into a set then verify for each item in the second is within the set. Unfortunately the HashSet<> is not available so the closest you can get is the Dictionary<,>.
Do this:
Dictionary<string, string> set = new Dictionary<string, string>();
foreach (string item in listA)
{
set.Add(item, item);
}
foreach (string item in listB)
{
if (!set.ContainsKey(item))
{
//Enable particular control
}
}

It's easy by using the Intersect method:
if (listB.Intersect(listA).Count() > 0)
{
//enable Control
}
else
{
//disable control
}

I think you are looking for something like this
List<string> lista = new List<string>() {"10","40","30" };
List<string> listb = new List<string>() { "10", "20" };
var diff = listb.Except<string>(lista);
diff should give you the ones which didn't match else all would have been matched.
For 2.0
if (listb.TrueForAll(delegate(string s2) { return lista.Contains(s2); }))
MessageBox.Show("All Matched");
else
MessageBox.Show("Not Matched");

In fx 2.0, you can do it like this:
string b = listA.Find(delegate(string a) { return listB.Contains(a); });
if (string.IsNullOrEmpty(b))
{
//disable control
}
else
{
//enable control
}

Control.Enabled = listB.Intersect(listA).Any()
Note that Any() will only check to see if there is at least one item. Count() > 0 will evaluate the entire collection when you only need to check if there is at least one item
Edit: If you are in a .NET 2.0 environment then you can loop through and do this:
foreach (int item in listB)
{
if (listA.Contains(item))
return true;
}
return false;

Related

Is It possible to find out what are the common part in String List

I was working on finding out the Common string part in the String list. If we take a sample data set
private readonly List<string> Xpath = new List<string>()
{
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(1)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(2)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(3)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(4)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(5)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(6)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(7)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(8)>H2:nth-of-type(1)",
"BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>SECTION:nth-of-type(9)>H2:nth-of-type(1)"
};
From this, I want to find out to which children these are similar. data is an Xpath list.
Programmatically I should be able to tell
Expected output:
BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV
In order to get this What I did was like this. I separate each item by > and then create a list of items for each dataset originally.
Then using this find out what are the unique items
private IEnumerable<T> GetCommonItems<T>(IEnumerable<T>[] lists)
{
HashSet<T> hs = new HashSet<T>(lists.First());
for (int i = 1; i < lists.Length; i++)
{
hs.IntersectWith(lists[i]);
}
return hs;
}
Able to find out the unique values and create a dataset again. But what happened is if this contains Ex:- Div in two places and it also in every originally dataset even then this method will pick up only one Div.
From then I would get something like this:
BODY>MAIN:nth-of-type(1)>DIV>SECTION
But I need this
BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-
type(3)>DIV>ARTICLE>DIV>DIV>DIV
Disclaimer: This is not the most performant solution but it works :)
Let's start with splitting the first path by > character
Do the same with all the paths
char separator = '>';
IEnumerable<string> firstPathChunks = Xpath[0].Split(separator);
var chunks = Xpath.Select(path => path.Split(separator).ToList()).ToArray();
Iterate through the firstPathChunks
Iterate through the chunks
if there is a match then remove the first element
if all first element is removed then append the matching prefix to sb
void Process(StringBuilder sb)
{
foreach (var pathChunk in firstPathChunks)
{
foreach (var chunk in chunks)
{
if (chunk[0] != pathChunk)
{
return;
}
chunk.RemoveAt(0);
}
sb.Append(pathChunk);
sb.Append(separator);
}
}
Sample usage
var sb = new StringBuilder();
Process(sb);
Console.WriteLine(sb.ToString());
Output
BODY>MAIN:nth-of-type(1)>DIV>SECTION>DIV>SECTION>DIV>DIV:nth-of-type(1)>DIV>DIV:nth-of-type(3)>DIV>ARTICLE>DIV>DIV>DIV>
Parsing the string by the seperator > is a good idea. Instead of then creating a list of unique items you should create a list of all items contained in the string which would result in
{
"BODY",
"MAIN:nth-of-type(1)",
"DIV",
"SECTTION",
"DIV",
...
}
for the first entry of your XPath list.
This way you create a List<List<string>> containing every element of each entry of your XPath list. You then can compare all first elements of the inner lists. If they are equal save that elements value to you output and proceed with all second elements and so on until you find an element that is not equal in all outer lists.
Edit:
After seperating your list by the > seperator this could look something like this:
List<List<string>> XPathElementsLists;
List<string> resultElements = new List<string>();
string result;
XPathElementsLists = ParseElementsFormXPath(XPath);
for (int i = 0; i < XPathElementsLists[0].Count; i++)
{
bool isEqual = true;
string compareElemment = XPathElementsLists[0][i];
foreach (List<string> element in XPathElementsLists)
{
if (!String.Equals(compareElemment, element))
{
isEqual = false;
break;
}
}
if (!isEqual)
{
break;
}
resultElements.Add(compareElemment);
}
result = String.Join(">", resultElements.ToArray());

in C# I want to compare two Lists

I have three lists
List1 < Labels > lbl and List2 < Strings > value and List3 < Strings > result
and I wanna compare both using foreach like
if (label1.text == value ) { // value is the 2nd list name
Label_Result.text = Result // in third List
Label1.font= new font("Tahoma",18);
ListBox1.items.add(Label.text);
}
Edit ,,
I think what I need is three Lists
Three basic examples. The first uses a simple nested foreach:
foreach(var item1 in list1)
foreach(var item2 in list2)
if(item1.text == item2)
{
//Do your thing
{
You could reduce nesting by using LINQ. Note that you could make this considerably fancier in LINQ (you can join lists), but I've chosen a simpelr example to show you the basic idea.
foreach(var item1 in list1)
{
var matchesInList2 = list2.Where(item2 => item1.text == item2);
foreach(var match in matchesInList2)
{
//Do your thing
}
}
There is a simpler way to approach it:
var matches = list1.Where(item1 => list2.Contains(item1.text));
foreach(var item1 in matches)
{
//Do your thing, e.g.:
//var theTextValue = item1.text;
}
To explain this simpler approach: we immediately filter list1, and only keep the elements whose .text value exists in list2.
After that, it is simply a matter of looping over the found matches, you don't need to filter anymore.
i think the best way is:
foreach(var list1item in lbl) //List1 item
{
foreach(var list2item in value) //List2 item
{
if(list1item == list2item)
{
//Do something
}
}
}

Adding to columns based on length

I have a ListView with two columns, Boxes and Files. I'm adding items to a list of strings, and then populating the ListView with that list of strings. I want to make it so all items that are 8 characters long go into the Boxes column and all items that are 9 characters go into the Files column. So far, I've tried to iterate through using a for loop and utilize an if else statement to add the items, but I seem to be doing something wrong. Here's my current code:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
var item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}
I'm iterating through my list (_boxAndFileList) and trying to utilize Insert() to insert items into the specific index of the columns (Boxes is 0, Files is 1). I can clearly see that Item is a legitimate property of a string list, yet VS keeps saying that list contains no definition of it. How can I go about doing this? And also, I haven't received outside feedback on this way of doing things yet, so if there's a better way, please let me know.
Edit: BoxNumberRepository is a class that news up a list called _boxAndFileList. Code below:
public class BoxNumberRepository : Scan_Form
{
public static List<string> _boxAndFileList = new List<string>();
public void AddItem(string item)
{
_boxAndFileList.Add(item);
}
public void Delete(string item)
{
_boxAndFileList.Remove(item);
}
public IEnumerable<string> GetAllItems()
{
return _boxAndFileList;
}
}
Thanks to Alessandro D'Andria for that suggestion. That was correct. However, all the items are still just adding to the first column, even if they're 9 characters. How can I get 9 character items to add to the second column?
The problem that you are having is that you have to add both the box and file to the list item at the same time.
EDIT: Changed cartesian product to a left outer join.
EDIT: Added comments and fixed a syntax bug
private List<string> _boxAndFileList = new List<string> { "12345678", "123456789", "1234", "123456778" };
public void PopulateItemsList()
{
//clear the list
BoxAndFileList.Items.Clear();
//add the labels to the top of the listbox
BoxAndFileList.Columns.Add("Boxes");
BoxAndFileList.Columns.Add("Files");
//set the view of the list to a details view (important if you try to display images)
BoxAndFileList.View = View.Details;
//clear scan id box
ScanIdBox.Text = string.Empty;
//get all the items whos length are 8 as well as a unique id (index)
var boxes = _boxAndFileList.Where(b => b.Length == 8).Select((b, index) => new { index, b }).ToList();
//get all the items whos length are NOT 8 as well as a unique id (index)
var files = _boxAndFileList.Where(f => f.Length != 8).Select((f, index) => new { index, f }).ToList();
//join them together on their unique ids so that you get info on both sides.
var interim = (from f in files
join b in boxes on f.index equals b.index into bf
from x in bf.DefaultIfEmpty()
select new { box = (x == null ? String.Empty : x.b), file = f.f });
//the real trick here is that you have to add
//to the listviewitem of type string[] in order to populate the second, third, or more column.
//I'm just doing this in linq, but var x = new ListViewItem(new[]{"myBox", "myFile"}) would work the same
var fileboxes = interim.Select(x => new ListViewItem(new []{ x.box, x.file})).ToArray();
//add the array to the listbox
BoxAndFileList.Items.AddRange(fileboxes);
//refresh the listbox
BoxAndFileList.Refresh();
}
Your _boxAndFileList is a List<string> so you should be declare item as string type instead var type:
string item = BoxNumberRepository._boxAndFileList.Item[i];
All your code should be like this:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
string item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}

how to dissect string values

How can I dissect or retrieve string values?
Here's the sample code that I'm working on now:
private void SplitStrings()
{
List<string> listvalues = new List<string>();
listvalues = (List<string>)Session["mylist"];
string[] strvalues = listvalues.ToArray();
for (int x = 0; x < strvalues.Length; x++)
{
}
}
Now that I'am able to retrieve list values in my session. How can I separately get the values of each list using foreach or for statement?
What I want to happen is to programmatically split the values of the strings depending on how many is in the list.
If you have a list of string values, you can do the following:
private void SplitStrings()
{
List<string> listValues = (List<string>) Session["mylist"];
// always check session values for null
if(listValues != null)
{
// go through each list item
foreach(string stringElement in listValues)
{
// do something with variable 'stringElement'
System.Console.WriteLine(stringElement);
}
}
}
Note that I test the result of casting the session and that I don't create a new list first-off, which is not necessary. Also note that I don't convert to an array, simply because looping a list is actually easier, or just as easy, as looping an array.
Note that you named your method SplitStrings, but we're not splitting anything. Did you mean to split something like "one;two;three;four" in a four-element list, based on the separator character?
I'm not sure what you're trying to obtain in this code, I don't know why you're converting your List to an Array.
You can loop through your listValues collection with a foreach block:
foreach(string value in listValues)
{
//do something with value, I.e.
Response.Write(value);
}
I don't know what's in the strings but you can start by simplifying. There is no point allocating a new List if you're going to overwrite it immediately.
private void SplitStrings()
{
List<string> list = (List<string>)Session["mylist"];
foreach(string value in list)
{
}
}
List listvalues = (List)Session["mylist"];
foreach (string s in listvalues)
{
//do what you want with s here
}

What's the pattern to use for iterating over associated sets of values?

It's pretty common - especially as you try to make your code become more data-driven - to need to iterate over associated collections. For instance, I just finished writing a piece of code that looks like this:
string[] entTypes = {"DOC", "CON", "BAL"};
string[] dateFields = {"DocDate", "ConUserDate", "BalDate"};
Debug.Assert(entTypes.Length == dateFields.Length);
for (int i=0; i<entTypes.Length; i++)
{
string entType = entTypes[i];
string dateField = dateFields[i];
// do stuff with the associated entType and dateField
}
In Python, I'd write something like:
items = [("DOC", "DocDate"), ("CON", "ConUserDate"), ("BAL", "BalDate")]
for (entType, dateField) in items:
# do stuff with the associated entType and dateField
I don't need to declare parallel arrays, I don't need to assert that my arrays are the same length, I don't need to use an index to get the items out.
I feel like there's a way of doing this in C# using LINQ, but I can't figure out what it might be. Is there some easy method of iterating across multiple associated collections?
Edit:
This is a little better, I think - at least, in the case where I have the luxury of zipping the collections manually at declaration, and where all the collections contain objects of the same type:
List<string[]> items = new List<string[]>
{
new [] {"DOC", "DocDate"},
new [] {"CON", "ConUserDate"},
new [] {"SCH", "SchDate"}
};
foreach (string[] item in items)
{
Debug.Assert(item.Length == 2);
string entType = item[0];
string dateField = item[1];
// do stuff with the associated entType and dateField
}
In .NET 4.0 they're adding a "Zip" extension method to IEnumerable, so your code could look something like:
foreach (var item in entTypes.Zip(dateFields,
(entType, dateField) => new { entType, dateField }))
{
// do stuff with item.entType and item.dateField
}
For now I think the easiest thing to do is leave it as a for loop. There are tricks whereby you can reference the "other" array (by using the overload of Select() that provides an index, for example) but none of them are as clean as a simple for iterator.
Here's a blog post about Zip as well as a way to implement it yourself. Should get you going in the meantime.
Create a struct?
struct Item
{
string entityType;
string dateField;
}
Pretty much the same as your Pythonic solution, except type-safe.
This is realy a variation on the other themes, but this would do the trick also...
var items = new[]
{
new { entType = "DOC", dataField = "DocDate" },
new { entType = "CON", dataField = "ConUserData" },
new { entType = "BAL", dataField = "BalDate" }
};
foreach (var item in items)
{
// do stuff with your items
Console.WriteLine("entType: {0}, dataField {1}", item.entType, item.dataField);
}
You can use the pair and a generic List.
List<Pair> list = new List<Pair>();
list.Add(new Pair("DOC", "DocDate"));
list.Add(new Pair("CON", "ConUserDate"));
list.Add(new Pair("BAL", "BalDate"));
foreach (var item in list)
{
string entType = item.First as string;
string dateField = item.Second as string;
// DO STUFF
}
Pair is part of the Web.UI, but you can easily create your own custom class or struct.
If you just want to declare the lists inline, you can do that in one step:
var entities = new Dictionary<string, string>() {
{ "DOC", "DocDate" },
{ "CON", "ConUserDate" },
{ "BAL", "BalDate" },
};
foreach (var kvp in entities) {
// do stuff with kvp.Key and kvp.Value
}
If they're coming from other things, we have a bunch of extension methods to build dictionaries from various data structures.

Categories

Resources