Why an IEnumerable is not adding items?
this code add itens to "values" list:
List<String> values = new List<String>();
for (int i = 0; i < ddlTransportadora.Items.Count; i++)
{
values.Add(ddlTransportadora.Items[i].Value);
}
but this code makes the loop, and after values doesn't have itens:
IEnumberable<String> values = new List<String>();
for (int i = 0; i < ddlTransportadora.Items.Count; i++)
{
values.Add(ddlTransportadora.Items[i].Value);
}
Any idea?
Because the Add method defined in IList<T> interface, and IEnumerable<T> doesn't inherit from IList<T>.You can use this instead:
IList<String> values = new List<String>();
for (int i = 0; i < ddlTransportadora.Items.Count; i++)
{
values.Add(ddlTransportadora.Items[i].Value);
}
All of these will give you an IEnumerable<string>:
You can use an explicit constructor to build and populate your collection:
new List<String>( ddlTransportadora.Items.Select( x => x.Value ) )
You can use LINQ to create an enumerable collection on the fly:
ddlTransportadora.Items.Select( x => x.Value ).ToList()
ddlTransportadora.Items.Select( x => x.Value ).ToArray()
You can even skip creating an actual collection and simply use LINQ deferred execution to provide an enumerable view of your data:
ddlTransportadora.Items.Select( x => x.Value )
Why try to make things any more complicated than they need to be?
Related
How to check duplicate string array in list?
I declare string array list like this:
List<string[]> list = new List<string[]>();
and I add a few items in the list.
list.Add(new string[3] {"1","2","3"});
list.Add(new string[3] {"2","3","4"});
list.Add(new string[1] {"3"});
list.Add(new string[1] {"3"});
list.Add(new string[3] {"1","2","3"});
now I want to get to know which items are duplicated. I tried like below to add the duplicated items to new list:
for (int j = 0; j < list.Count - 1; j++)
{
for (int k = list.Count - 1; k > j; k--)
{
if (j != k)
{
if (Enumerable.SequenceEqual(list[j], list[k]))
{
savedDistinctList.Add(list[j]);
}
}
}
}
and finally I want to remove the duplicated item in the first list. so I want to see 3 items in the list.([1,2,3],[2,3,4],[3])
Perhaps any idea using LINQ or something else?
First we have to teach .Net how to compare arrays:
private sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]> {
public bool Equals(T[] left, T[] right) {
if (ReferenceEquals(left, right))
return true;
if (left is null || right is null)
return false;
return left.SequenceEqual(right);
}
public int GetHashCode(T[] array) => array is null
? -1
: array.Length;
}
Then you can use Linq Distinct with this class implemented:
using System.Linq;
...
savedDistinctList = list
.Distinct(new ArrayEqualityComparer<string>())
.ToList();
If you want to modify the existing list, you can use HashSet<T>:
var unique = new HashSet<string[]>(new ArrayEqualityComparer<string>());
for (int i = list.Count - 1; i >= 0; --i)
if (!unique.Add(list[i]))
list.RemoveAt(i);
This has already been replied here: C# LINQ find duplicates in List by #Save
The easiest way to solve the problem is to group the elements based on their value, and then pick a representative of the group if there are more than one element in the group. In LINQ, this translates to:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();
If you want to know how many times the elements are repeated, you can use:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Element = y.Key, Counter = y.Count() })
.ToList();
This will return a List of an anonymous type, and each element will have the properties Element and Counter, to retrieve the information you need.
And lastly, if it's a dictionary you are looking for, you can use
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.ToDictionary(x => x.Key, y => y.Count());
This will return a dictionary, with your element as key, and the number of times it's repeated as value.
Apply with a foreach on your list.
Trying to iterate through a session key I have, collect the values into a list, and then compare it to a database.
I have tried:
List<Model> listVar = new List<Model>();
for(int i = 0; i < ids.Count; i++)
{
int index = arrayValue[i]
listVar = databasemodel.table.Where(s => s.id == index).ToList()
}
It's only grabbing one of the values though when I do this, kinda new to Linq. Is there a method I can use instead of what I am doing now?
I had a simlar issue before, I used the .Contains() method.. as follows:
.Where(s => id.Contains(s.id));
That should work.
Supposing the s.id is an integer then you need to add the results of your WHERE expression to the final list
var selectedids = new List<int>();
for(int i = 0; i < ids.Count; i++)
{
int index = arrayValue[i];
selectedIds.AddRange(databasemodel.table.Where(s => s.id == index));
}
so I have a list:
["item1"]
["item2"]
["item3"]
and I want the list to be like this:
[""]
["item1"]
[""]
["item2"]
[""]
["item3"]
A simple back-to-front loop gives me just that:
for (int i = list.Count-1; i >= 0; i--)
list.Insert(i, string.Empty);
But I'm wondering if there is a more elegant way to do this with LINQ?
You could use an Intersperse extension method. That way, the meaning is clear and the code is reusable. Code taken from Extension method for Enumerable.Intersperse with slight modification to also include an empty string in the first position.
public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element)
{
foreach (T value in source)
{
yield return element;
yield return value;
}
}
Here is a way to do it:
list = list.SelectMany(x => new [] { string.Empty, x }).ToList();
But it's worth noting that this creates unnecessary arrays.If your list is big enough that might be a problem. Instead I would create a new list with a capacity and populate it using loop:
var newList = new List<string>(list.Count * 2);
int j = 0;
for(int i = 0; i < list.Count * 2; i++)
newList.Add(i % 2 == 0 ? string.Empty : list[j++]);
This will avoid resizing the list each time you add or insert items.
You can do it using SelectMany LINQ extension:
void Main()
{
List<String> items = new List<String>()
{
"1",
"2",
"3"
};
var result = items
.SelectMany(item => new String[] {"Some value", item})
.ToList();
PrintItems(result);
}
void PrintItems<T>(IEnumerable<T> items)
{
foreach(var item in items)
{
Console.WriteLine(item);
}
}
But as you understand it is not the most effective way.
Another one-liner using Aggregate:
List<string> result = list.Aggregate(new List<string>(list.Count * 2), (a, x) => { a.Add(""); a.Add(x); return a; });
I need to create pairs / triples of something and store it somewhere. How can I do it?
I tried:
for (int i = 0; i < 100; i++)
{
var item=new { a=i , b="lala" ,c=4.5m}; //anonymous type
}
But then I thought: List<what>?
I could use dynamic but I want Intellisense.
(I could have also use Tuple<int,string,decimal> but if I already have what I need (=new { a=i , b="lala" ,c=4.5m};), why should I use other type (tuple)? )
Is there any solution to this?
You can use type inference
var items = Enumerable.Range(0,100)
.Select(i => new { a=i , b="lala", c=4.5m })
.ToList(); // not necessary (you can use IEnumerable)
Not sure, how you fill fields within for, but could you try:
var lstOfSmth = Enumerable.Range(0, 100)
.Select(i => new { a = i, b = "lala", c = 4.5m })
.ToList();
why should I use other type (tuple)
Because they have been designed exactly for this purpose. If you're afraid of verbose code, the using directive comes to the rescue, too.
using myPair = Tuple<int,string>;
using myTriple = Tuple<int,string,decimal>;
//...
for (int i = 0; i < 100; i++)
{
myPair pair = new myPair(1,"string");
myTriple triple = new myTriple(i,"lala", 4.5);
}
int x = 9;
List<string> list = new List<string> {"a", "b"};
I want list to be: a b a b a ... until list.Count = x. How might I achieve this?
You could do it with LINQ easily:
List<string> result = (from ignored in Enumerable.Range(0, int.MaxValue)
from item in list
select item).Take(count).ToList();
Or without using a query expression:
List<string> result = Enumerable.Range(0, int.MaxValue)
.SelectMany(ignored => list)
.Take(count)
.ToList();
The use of Enumerable.Range here is just to force repetition - like Ani's approach of using Enumerable.Repeat, which will work too of course.
How about:
var result= Enumerable.Repeat(new[] { "a", "b" }, int.MaxValue)
.SelectMany(strArray => strArray)
.Take(x)
.ToList();
Something like this should work. I did not check it, let it be an exercise for you :)
int currentCount = list.Count;
for (int i=0; i<x; ++i)
{
list.Add(list[i%currentCount]);
}
int x = 9;
List<string> list = new List<string> {};
for (int i = 0; i < x; i++)
{
list.Add("a");
list.Add("b");
}
// verify
foreach (var item in list)
{
Console.WriteLine(item);
}