Distinct items in List - c#

I have an excel spreadsheet that I am trying to populate a list with only unique values. I have found LinqToExcel which I would prefer not to use. At most there will be 2000 rows which isn't very much.
My thought was:
List<string> lst = new List<string>();
string item;
for (i=2; i<2001; i++)
{
item = ws.cells[i,3];
if(lst.**notInList**(item))
{
lst.Add(item);
}
}
I know that there isn't notInList(), but I was hoping for something similar or another idea.

var values = Enumerable.Range(2, 1999)
.Select(i => ws.cells[i,3])
.Distinct()
.ToList();

Use Contains instead
List<string> lst = new List<string>();
string item;
for (i=2; i<2001; i++)
{
item = ws.cells[i,3];
if(!lst.Contains(item))
{
lst.Add(item);
}
}

List<string> lst = new List<string>();
string item;
for (i=2; i<2001; i++)
{
item = ws.cells[i,3];
if(!lst.Contains(item))
{
lst.Add(item);
}
}

If you want the items filtered for identical entries, you could use the .Distinct method from linq.
var distinctList = lst.Distinct();
There's also List.Contains(item)
If you know from the get-go that this collection should contain only unique elements, also consider using a HashSet<T> instead.

Related

Get listitems according to the index of another list

I have a List<List<string>> with three nested lists. Now I need to check if List[1] equals a certain string and if so, check if the value at this index in List[2] has another certain string. If both conditions return true, then I need to get that certain index and get the item of List[0].
For example:
var list = Titles[0];
var list2 = Titles[1];
var list3 = Titles[2];
foreach (var item in list2)
{
if (item.Contains("Dt."))
{
int idx = list2.IndexOf(item);
var value = list3.ElementAt(idx);
if (value.Contains("25.04.2017"))
{
var newList = list.ElementAt(idx);
}
}
}
This approach doesn't seem very efficient in regards to performance, especially if the nested list contains ~9000 items.
I tried to get the result via lambda expressions first, but I'm not sure if this is the right approach either.
What would be the best or most efficient solution?
Eliminate ElementAt with direct access to index. I believe ElementAt iterates over List in order to get i'th element
Eliminate usage of IndexOf with index provided by for loop I believe IndexOf iterates over List in order to find matching element.
var list = Titles[0];
var list2 = Titles[1];
var list3 = Titles[2];
for (int i = 0 ; i < list2.Count; ++ i)
{
var item = list2[i];
if (item.Contains("Dt."))
{
var value = list3[i];
if (value.Contains("25.04.2017"))
{
var newList = list[i];
}
}
}
Note if size of list2 is greater than size of list or list3 then you potentially get IndexOutOfRangeException
Lambda equivalent for your code:
if(list2.Any(item => item.Contains("Dt.")))
{
int idx = list2.IndexOf("Dt.");
if(list3.ElementAt(idx).Contains("25.04.2017"))
{
var newList = list.ElementAt(idx);
}
}
for (int i = 0; i < list2.Count; ++i)
{
var item = list2[i];
if (item.Contains("Dt."))
{
var value = list3[i];
if (value.Contains("25.04.2017"))
{
var newList = list[i];
break; // Break the loop :-)
}
}
}

How to add a collection of list into a list?

I have my code like,
List<string> list = new List<string>();
model.QuestionSetList = new List<string>();
for (int i = 0; i < response.QuestionsInfoList.Count(); i++)
{
list.Add(response.QuestionSetInfo.QuestionsInfoList[i].Question);
foreach (AnswerSetContract answerSetContract in response.QuestionsInfoList[i].AnswersInfoList)
{
list.Add(answerSetContract.AnswerText);
}
model.QuestionSetList.Add(list)
}
I cannot add a list into another list.Kindly tell me what to do in this case.
Look at the Concat function within the System.Linq namespace
I.e.
using System.Linq;
List<string> list = new List<string>();
model.QuestionSetList = new List<string>();
for (int i = 0; i < response.QuestionsInfoList.Count(); i++)
{
list.Add(response.QuestionSetInfo.QuestionsInfoList[i].Question);
foreach (AnswerSetContract answerSetContract in response.QuestionsInfoList[i].AnswersInfoList)
{
list.Add(answerSetContract.AnswerText);
}
model.QuestionSetList = model.QuestionSetList.Concat(list);
}
But why not at the place of; list.Add(answerSetContract.AnswerText); add it directly to model.QuestionSetList?
So like this;
List<string> list = new List<string>();
model.QuestionSetList = new List<string>();
for (int i = 0; i < response.QuestionsInfoList.Count(); i++)
{
list.Add(response.QuestionSetInfo.QuestionsInfoList[i].Question);
foreach (AnswerSetContract answerSetContract in response.QuestionsInfoList[i].AnswersInfoList)
{
model.QuestionSetList.Add(answerSetContract.AnswerText);
}
}
If you want a List of Lists, then your QuestionSetList would have to be:
model.QuestionSetList = new List<List<<string>>()
Consider creating a custom type though, otherwise it's a bit like inception, list in a list in a list in a list.........
Or if you're actually wanting to combine the Lists, then use Concat:
list1.Concat(list2);
You should try with AddRange, it allows to add a collection to a List
http://msdn.microsoft.com/en-us/library/z883w3dc.aspx
model.QuestionSetList is a list of strings.
You're trying to add a list of strings to it. As their types are incompatible, it won't allow you to do that.
Try making model.QuestionSetList a List<List<string>> and see if that helps you.

How I get a Arraylist with not double values?

I want do get a Departmentlist from the Active Directory for this I use the Directoryentry and the DirectorySearcher class. I get the list of departments but how I can delete the double values in this list.
for example my list now:
it
it
it
vg
per
vg
...
And I want only one of this values in the list how this:
it
vg
per
...(other departments)
I want to use this list for a dropDownlist list.
my Code:
public static void GetAllDepartments(string domaincontroller)
{
ArrayList list = new ArrayList();
int Counter = 0;
string filter = "(&(objectClass=user)(objectCategory=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(sn=*)(|(telephoneNumber=*)(mail=*))(cn=*)(l=*))";
List<User> result = new List<User>();
DirectoryEntry Entry = new DirectoryEntry(domaincontroller);
DirectorySearcher Searcher = new DirectorySearcher(Entry, filter);
foreach (SearchResult usr in Searcher.FindAll())
{
result.Add(new User()
{
department = GetLdapProperty(usr, "Department")
});
Counter++;
}
for (int i = 0; i < Counter; i++)
{
list.Add(result[i].department);
}
}
How I can show only one value in the Arraylist?
First of all, I recommend that instead of using an ArrayList, use a Strongly-Typed list.
Then, use the Distinct() method to only get a list of unique values (no duplicates).
For instance:
List<String> list = new List();
....
for (int i = 0; i < Counter; i++)
{
list.Add(result[i].department.ToString());
}
var noDuplicates = list.Distinct();
Try Distinct() in System.Linq extensions :
list = list.Distinct();
You can also use the Exists clause to see if the element already exists in the list.
using System.Linq;
for (int i = 0; i < Counter; i++)
{
bool deptExists = list.Exists(ele => ele == result[i].department);
if(!deptExists){
list.Add(result[i].department);
}
}
Use the Enumerable.Distinct Method method.
Use a HashSet and only insert the non-duplicate values.
HashSet<string> list = new HashSet<string>();
...
for (int i = 0; i < Counter; i++)
{
string dep = result[i].department.ToString();
// true if dep was added, false if not. No exception at this point.
list.Add(dep);
}

how to add the selected item from a listbox to list <string> in c#

how to add the selected item from a listbox to list to get the username that are selected
my code:
List<String> lstitems = new List<String>();
foreach (string str in lstUserName.SelectedItem.Text)
{
lstitems.Add(str);
}
it show me error saying cannot convert char to string.... how to add the items to list or array
You need to use the SelectedItems property instead of SelectedItem:
foreach (string str in lstUserName.SelectedItems)
{
lstitems.Add(str);
}
EDIT: I just noticed this is tagged asp.net - I haven't used webforms much but looking at the documentation it seems this should work:
List<string> listItems = listBox.GetSelectedIndices()
.Select(idx => listBox.Items[idx])
.Cast<string>()
.ToList();
I note that you're using ASP.
For standard C# the following would work:
List<string> stringList = new List<string>();
foreach (string str in listBox1.SelectedItems)
{
stringList.Add(str);
}
If there's only one selected item:
List<String> lstitems = new List<String>();
lstitems.Add(lstUsername.SelectedItem.Value);
Here's a method for getting multiple selections since System.Web.UI.WebControls.ListBox doesn't support SelectedItems:
// Retrieve the value, since that's usually what's important
var lstitems = lstUsername.GetSelectedIndices()
.Select(i => lstUsername.Items[i].Value)
.ToList();
Or without LINQ (if you're still on 2.0):
List<string> lstitems = new List<string():
foreach(int i in lstUsername.GetSelectedIndices())
{
lstitems.Add(lstUsername[i].Value);
}
You can also do this
List<String> lstitems = new List<String>();
for (int i = 0; i < ListBox1.Items.Count; i++)
{
if (ListBox1.Items[i].Selected)
lstitems.Add(ListBox1.Items[i].Value);
}
If you are using a button to add selected 'item' in string list, just do this.
private void button1_Click(object sender, EventArgs e)
{
List<string> selectedItems = new List<string>();
string item = listBox1.SelectedItem.ToString();
if (!selectedItems.Contains(item))
{
selectedItems.Add(item);
}
}
You can do this in one operation:
IEnumerable<string> groupList = groupsListBox.SelectedItems.Cast<string>();
It will always work for custom objects too:
IEnumerable<CustomObject> groupList = groupListBox.SelectedItems.Cast<CustomObject>();

Merge and Update Two Lists in C#

I have two List<T> objects:
For example:
List 1:
ID, Value where Id is populated and value is blank and it contains say IDs from 1 to 10.
1,""
2,""
...
10,""
List 2:
ID, Value and other attributes all filled with values but this list is a subset of List 1 in terms of IDs. (e.g only 3 items)
2,67
4,90
5,98
What I want is a merged list 1, but with updated values. Does anyone have any good extension method which will do this or any elegent code to perform this operation. The final list should be:
ID, Value
1,""
2,67 //value from list 2
3,""
4,90
5,98
6,""
...
10,""
use linq: list1=list2.Union(list1);
I would probably use a dictionary rather than a list:
// sample data
var original = new Dictionary<int, int?>();
for (int i = 1; i <= 10; i++)
{
original.Add(i, null);
}
var updated = new Dictionary<int, int>();
updated.Add(2, 67);
updated.Add(4, 90);
updated.Add(5, 98);
updated.Add(11, 20); // add
// merge
foreach (var pair in updated)
{
original[pair.Key] = pair.Value;
}
// show results
foreach (var pair in original.OrderBy(x => x.Key))
{
Console.WriteLine(pair.Key + ": " + pair.Value);
}
If you are talking about properties of an object, it will be trickier, but still doable.
This is O(m*n) but should do the job for arbitrary lists
foreach (var record in List1)
{
var other = List2.FirstOrDefault(x => x.Key == record.Key);
if(other != null) record.Value = other.Value;
}
If the lists are guaranteed ordered, then it could be brought down to O(n) at the cost of more code. The algortihm would be
Current items start as head of each list
While items remain in both lists
If the current item of list1 has lower key than list2 advance to next in list1
else if the current item of list2 has lower key than list1 advance to next in list2
else copy value from current list2 item into list1 item and advance both lists.
If you have both lists sorted by ID, you can use a variation of the classical merge algorithm:
int pos = 0;
foreach (var e in list2) {
pos = list1.FindIndex(pos, x => x.Id==e.Id);
list1[pos].Value = e.Value;
}
Note that this also requires list2 to be a strict subset of list1 in terms of ID (i.e. list1 really contains all ids of list2)
Of course you can also wrap this in an extension method
public static void UpdateWith<T>(this List<T> list1, List<T> list2)
where T:SomeIdValueSupertype {
int pos = 0;
foreach (var e in list2) {
pos = list1.FindIndex(pos, x => x.Id==e.Id);
list1[pos].Value = e.Value;
}
}
private void btnSearch_Click(object sender, EventArgs e)
{
String searchBy = cmbSearchBy.Text.ToString();
String searchFor = txtSearchFor.Text.Trim();
var List3 = (from row in JobTitleDB.jobList
where (row.JID.ToString()+row.JobTitleName.ToString().ToLower()).Contains(searchFor.ToLower())
select row).ToList();
if (searchBy == "All")
{
dgJobTitles.DataSource = null;
//dgJobTitles.DataSource = List1;
//dgJobTitles.DataSource = List2;
//dgJobTitles.DataSource = List1.Concat(List2);
//dgJobTitles.DataSource = List1.Union(List2);
dgJobTitles.DataSource = List3;
//dgJobTitles.DataSource=List1.AddRange(List2);
}
}
Dictionary<int, string> List1 = new Dictionary<int, string>();
List1.Add(1,"");
List1.Add(2,"");
List1.Add(3,"");
List1.Add(4,"");
List1.Add(5,"");
List1.Add(6,"");
Dictionary<int, string> List2 = new Dictionary<int, string>();
List2.Add(2, "two");
List2.Add(4, "four");
List2.Add(6, "six");
var Result = List1.Select(x => new KeyValuePair<int, string>(x.Key, List2.ContainsKey(x.Key) ? List2[x.Key] : x.Value)).ToList();

Categories