C# Join two List<int>, remove duplicates, NO LINQ - c#

This is the idea: I have two List<int> and I want to make a third List<int> with the above mentioned lists joined, without duplicates. I know how to use .Union but I want to make this without using LINQ. So far I have this:
Console.WriteLine("Enter numbers for first list: ");
List<int> firstList = new List<int>{20, 40, 10, 10, 30, 80};
//Console.ReadLine().Split(' ').Select(int.Parse).ToList();
Console.WriteLine("Enter numbers for second list: ");
List<int> secondList = new List<int> {25, 20, 40, 30, 10 };
//Console.ReadLine().Split(' ').Select(int.Parse).ToList();
List<int> newList = new List<int>();
foreach (var item in firstList)
{
if (secondList.Contains(item))
{
continue;
}
}
newList.Sort();
newList.ForEach(p => Console.WriteLine(p));
And I am actually stuck...I think that I need to iterate each one of the lists and if the items are equal, add them just once to the new list...But I can't seem to figure out how to do that if the lists are different count.
Any ideas?

This is presented with a big (and I do mean big) caveat - it's going to be slow. You will get much better performance from using LINQ or a different collection (eg. HashSet). This approach is O(n^2) whereas LINQ etc. is O(n).
Simply loop over the second list adding the value to the first if it's not already in the list.
foreach (var item in secondList)
{
if (!firstList.Contains(item))
{
firstList.Add(item);
}
}
Given that you want a new list at the end of the process you can just add all the items from the first list to the result before the above code:
foreach (var item in firstList)
{
newList.Add(item);
}
and replace firstList with newList when adding.

You could take advantage of different types of collections to do the following:
var set = new HashSet<int>(firstList);
set.UnionWith(secondList);
var newList = new List<int>(set);

Something like this?
newList.AddRange(firstList);
newList.AddRange(secondList);
newList = newList.Distinct().ToList();
newList.Sort();

Related

Selenium List Sort Order Comparison C#

I have a typical web page that has check boxes to filter on and then there is a drop down to sort by low to high and high to low. The list/xpath code below returns 25 elements with varying prices.
What I want to do is assert that when I select the sort option from low to high, that my prices should look like $10, $10, $12, $15, etc. What is my next step here? It has been awhile since I have worked with list and my mind is drawing a blank.
I think I used Linq last time, sorted the results and ran a compare but after looking at this for three hours I have gone brain dead.
Suggestions?
public List<string> GetInitialSortByPrice ()
{
List<String> item = new List<string>();
IReadOnlyList<IWebElement> cells =
Browser.FindElements_byXpath("//h4[#class='price']");
foreach (IWebElement cell in cells)
{
item.Add(cell.Text);
}
return item;
}
Solution....
List<String> item = new List<string>();
IReadOnlyList<IWebElement> cells =
Browser.FindElements_byXpath("//h4[#class='price']");
foreach (IWebElement cell in cells)
{
item.Add(cell.Text.Replace("$", ""));
}
List<decimal> listA = item.Select(s =>
decimal.Parse(s)).ToList();
List<decimal> listB = listA.OrderBy(x => x).ToList();
Assert.IsTrue(listA.SequenceEqual(listB));
This was for the descending order:
List<decimal> listB = listA.OrderByDescending(i => i).ToList();

How do I remove duplicates from excel range? c#

I've converted cells in my excel range from strings to form a string list and have separated each item after the comma in the original list. I am starting to think I have not actually separated each item, and they are still one whole, trying to figure out how to do this properly so that each item( ie. the_red_bucket_01)is it's own string.
example of original string in a cell 1 and 2:
Cell1 :
the_red_bucket_01, the_blue_duck_01,_the green_banana_02, the orange_bear_01
Cell2 :
the_purple_chair_01, the_blue_coyote_01,_the green_banana_02, the orange_bear_01
The new list looks like this, though I'm not sure they are separate items:
the_red_bucket_01
the_blue_duck_01
the green_banana_02
the orange_bear_01
the_red_chair_01
the_blue_coyote_01
the green_banana_02
the orange_bear_01
Now I want to remove duplicates so that the console only shows 1 of each item, no matter how many there are of them, I can't seem to get my foreah/if statements to work. It is printing out multiple copies of the items, I'm assuming because it is iterating for each item in the list, so it is returning the data that many items.
foreach (Excel.Range item in xlRng)
{
string itemString = (string)item.Text;
List<String> fn = new List<String>(itemString.Split(','));
List<string> newList = new List<string>();
foreach (string s in fn)
if (!newList.Contains(s))
{
newList.Add(s);
}
foreach (string combo in newList)
{
Console.Write(combo);
}
You probably need to trim the strings, because they have leading white spaces, so "string1" is different from " string1".
foreach (string s in fn)
if (!newList.Contains(s.Trim()))
{
newList.Add(s);
}
You can do this much simpler with Linq by using Distinct.
Returns distinct elements from a sequence by using the default
equality comparer to compare values.
foreach (Excel.Range item in xlRng)
{
string itemString = (string)item.Text;
List<String> fn = new List<String>(itemString.Split(','));
foreach (string combo in fn.Distinct())
{
Console.Write(combo);
}
}
As mentioned in another answer, you may also need to Trim any whitespace, in which case you would do:
fn.Select(x => x.Trim()).Distinct()
Where you need to contain keys/values, its better to use Dictionary type. Try changing code with List<T> to Dictionary<T>. i.e.
From:
List<string> newList = new List<string>();
foreach (string s in fn)
if (!newList.Containss))
{
newList.Add(s);
}
to
Dictionary<string, string> newList = new Dictionary<string, string>();
foreach (string s in fn)
if (!newList.ContainsKey(s))
{
newList.Add(s, s);
}
If you are concerned about the distinct items while you are reading, then just use the Distinct operator like fn.Distinct()
For processing the whole data, I can suggest two methods:
Read in the whole data then use LINQ's Distinct operator
Or use a Set data structure and store each element in that while reading the excel
I suggest that you take a look at the LINQ documentation if you are processing data. It has really great extensions. For even more methods, you can check out the MoreLINQ package.
I think your code would probably work as you expect if you moved newList out of the loop - you create a new variable named newList each loop so it's not going to find duplicates from earlier loops.
You can do all of this this more concisely with Linq:
//set up some similar data
string list1 = "a,b,c,d,a,f";
string list2 = "a,b,c,d,a,f";
List<string> lists = new List<string> {list1,list2};
// find unique items
var result = lists.SelectMany(i=>i.Split(',')).Distinct().ToList();
SelectMany() "flattens" the list of lists into a list.
Distinct() removes duplicates.
var uniqueItems = new HashSet<string>();
foreach (Excel.Range cell in xlRng)
{
var cellText = (string)cell.Text;
foreach (var item in cellText.Split(',').Select(s => s.Trim()))
{
uniqueItems.Add(item);
}
}
foreach (var item in uniqueItems)
{
Console.WriteLine(item);
}

How to break from the loop when adding values to the list object which is distinct from already added values of the list?

i have one list object which contains int like below:
var list = new List<int>();
var ids=getting only ids from database.for Eg:1,2,1,3,5,6,3.
Now what i want to do is after fetching ids from datatabase i want to add in to my list object and if any differnt ids is added(eg:ids:2) then i want to break from the loop.
For Ex: After adding 1 in my list now if i try to add 2 which doesnt exist in my list object then i want to break from my loop with status different element found outside the loop.
Add values in the list object till duplicate value is found means add only duplicate values in my list object and if distinct value is found which is not already in the list then break from loop.Break from the loop after adding 1 in list because 2 is different and it is not already in the list object.
This is my code:
bool status;
for (var i = 0; i < ids.Count; i++)
{
list.Add(ids);
}
//here i want status with different element found or not
Note:I just want to add only duplicates values in my list object until new id is found.
i just want to add duplicate values in list object until different ids is found.
var list = new List<int>{ 1, 2, 3, 4};
var idsFromDb = new List<int> {1, 2, 5, 3};
foreach (int id in idsFromDb)
{
if (list.Contains(id))
{
break;
}
list.Add(id);
}
You can use foreach to iterate over elements of ids
break works in foreach just the way it does in for
if we don't break, do whatever you want to do, for example, add the value to list
Contains checks if list already contains id.
This makes it roughly an O(n^2) operation - because both foreach and Contains iterate over elements of list
Code:
foreach (var id in ids)
{
if (list.Contains(id))
{
break;
}
list.Add(id);
}
You can use Contains
status = false;
for (var i = 0; i < ids.Count; i++)
{
if (list.Count > 0 && !list.Contains(ids[i])){
list.Add(ids[i]); //add this, be it duplicate or not
status = true; //different element found
break; //break if this is not duplicate
} else {
//do something for duplicate
list.Add(ids[i]); //add this, be it duplicate or not
}
}
Contains can check if your item already exists in the List
Here's your desired HashSet<T> + LINQ approach:
var dupChecker = new HashSet<int> {ids[0]}; // add first element, now only duplicates are allowed
List<int> dupList = ids.TakeWhile(i => !dupChecker.Add(i)).ToList();

How to reverse the order of displaying content of a list?

Let's say I have a list of integers.
var myList = new List<int>();
1, 2, 3, 4, 5, ..., 10
Is there any function that allows me to display them in reverse order, i.e.
10, 9, 8, ..., 1
EDIT
public List<Location> SetHierarchyOfLocation(Location location)
{
var list = new List<Location>(7);
var juridiction = location.Juridiction;
if (juridiction > 0)
{
while (juridiction > 0)
{
var loc = repository.GetLocationByID(juridiction);
list.Add(loc);
juridiction = loc.Juridiction;
}
}
return list;
}
Since the list contains location by location, I want to be able to display it by reversed order as well.
Now, when I write return list.Reversed(), I get the error.
Thanks for helping
var reversed = myList.Reverse() should do the trick.
EDIT:
Correction- as the OP found out, List.Reverse works in-place, unlike Enumerable.Reverse. Thus, the answer is simply myList.Reverse(); - you don't assign it to a new variable.
Is there any function that allows me to display them in reverse order, i.e.
It depends if you want to reverse them in place, or merely produce a sequence of values that is the reverse of the underlying sequence without altering the list in place.
If the former, just use List<T>.Reverse.
// myList is List<int>
myList.Reverse();
Console.WriteLine(String.Join(", ", myList));
If the latter, the key is Enumerable.Reverse:
// myList is List<int>
Console.WriteLine(
String.Join(
", ",
myList.AsEnumerable().Reverse()
)
);
for a beautiful one-liner. Be sure you have using System.Linq;.
To do a foreach loop in a List<Location> reversely you should use:
foreach (Location item in myList.Reverse().ToList())
{
// do something ...
}
The .Reverse() is an in-place reverse; it doesn't return a new list. The .ToList() after the .Reverse() do the trick.

idictionary help filtering items

Is there a better way to code the Where this:
IDictionary<string, string> p = new Dictionary<string, string>();
p.Add("Apple", "1");
p.Add("Orange", "2");
p.Add("Pear", "3");
p.Add("Grape", "4");
p.Add("Pineapple", "5");
//This is a unique list
var retVal = p.Where(k => k.Key.Contains("Apple") || k.Key.Contains("Pear") || k.Key.Contains("Grape"));
Some History Below
I have a dictionary of strings like the following:
IDictionary<string,string>
The contents look like this:
Apple,1
Orange,2
Pear,3
Grape,4
...many more
How do i return only a few items from my dictionary like so
if (true)
{
//return only 3 apple,pear&grape items out of the dozens in the list into a new variable
}
You can just take the first 3 items...
theDictionary.Take(3);
Or filter and take specific items...
string[] itemsIWant = { "Apple", "Pear", "Grape" };
theDictionary.Where(o => itemsIWant.Contains(o.Key));
Or sort randomly and take 3...
Random r = new Random();
theDictionary.OrderBy(o => r.Next()).Take(3);
check out
LINQ query to return a Dictionary<string, string>
That will really depend on the kind of filtering you want to achieve. But you can achieve it through Linq.
If you just want to get the first 3 items, you can do it like this:
theDictionary.Take(3);
If you want to get the first 3 items that begin with 'G', the you will do this:
theDictionary.Where(kv => kv.Key.StartsWith("G")).Take(3);
If you want to get the first 3 items that begin with 'G' regardless the casing, the you will do this:
theDictionary.Where(kv => kv.Key.ToLower().StartsWith("g")).Take(3);
Last, but not least, if you want to get 3 items randomly, you will do this:
Random rand = new Random();
theDictionary.OrderBy(kv => rand.Next()).Take(3);

Categories

Resources