How to convert nested loop to a LINQ-statement? - c#

A rather simple question, but I can't work out how to convert a nested loop of such a kind:
for (var a = 0; a < n; a++)
{
for (var b = a + 1; b < n; b++)
{
//let here be a creation of a Tuple
list.Add(Tuple.Create(a, b))
}
}
to a LINQ-statement
upd:
I tried something like this:
from a in Enumerable.Range(0, n)
from b in Enumerable.Range(1, n)
...
but it didn't work

Alright, here is one solution using Linq extension methods.
var list = Enumerable.Range(0, n-1)
.SelectMany(
a => Enumerable.Repeat(a, n-1 - a)
.Zip( Enumerable.Range(a+1, n - (a+1)) )
).ToList();
How does it work? Well, look up the documentation for the involved Linq methods, that should provide sufficient insight to what's going on here with that ugly Linq construct of mine. (Well, it's not only ugly, it's also so slow you are not at any risk of violating any speed limit...)
Note that the generated list is of type System.Collections.Generic.List<(int First, int Second)>, which is using C# tuples, which are a value types and not to be confused with the System.Tuple type (which is a reference type) you used in the code in your question.
And here is a solution involving Linq query syntax:
var list = (
from a in Enumerable.Range(0, n - 1)
from b in Enumerable.Range(a + 1, n - (a + 1))
select (a, b)
).ToList();

It could be helpfull.
var result = (from a in Enumerable.Range(0, n - 1)
from b in Enumerable.Range(a + 1, n - a - 1)
select Tuple.Create(a, b)).ToList();

You may use this:
Enumerable.Range(0, n-1).ToList().ForEach(x => Enumerable.Range(x + 1, n-x-1).ToList().ForEach(y => list.Add(Tuple.Create(x,y))));

Related

How to create new list from list of list where elements are in new list are in alternative order? [duplicate]

This question already has answers here:
Interleaving multiple (more than 2) irregular lists using LINQ
(5 answers)
Closed 5 years ago.
Suppose I have list of list. I want to create new list from given list of list such that elements are in order of example given below.
Inputs:-
List<List<int>> l = new List<List<int>>();
List<int> a = new List<int>();
a.Add(1);
a.Add(2);
a.Add(3);
a.Add(4);
List<int> b = new List<int>();
b.Add(11);
b.Add(12);
b.Add(13);
b.Add(14);
b.Add(15);
b.Add(16);
b.Add(17);
b.Add(18);
l.Add(a);
l.Add(b);
Output(list):-
1
11
2
12
3
13
4
14
15
16
And output list must not contain more than 10 elements.
I am currently doing this using foreach inside while but I want to know how can I do this using LINQ.
int loopCounter = 0,index=0;
List<int> o=new List<int>();
while(o.Count<10)
{
foreach(List<int> x in l)
{
if(o.Count<10)
o.Add(x[index]);
}
index++;
}
Thanks.
Use the SelectMany and Select overloads that receive the item's index. That will be used to apply the desired ordering. The use of the SelectMany is to flatten the nested collections level. Last, apply Take to retrieve only the desired number of items:
var result = l.SelectMany((nested, index) =>
nested.Select((item, nestedIndex) => (index, nestedIndex, item)))
.OrderBy(i => i.nestedIndex)
.ThenBy(i => i.index)
.Select(i => i.item)
.Take(10);
Or in query syntax:
var result = (from c in l.Select((nestedCollection, index) => (nestedCollection, index))
from i in c.nestedCollection.Select((item, index) => (item, index))
orderby i.index, c.index
select i.item).Take(10);
If using a C# 6.0 and prior project an anonymous type instead:
var result = l.SelectMany((nested, index) =>
nested.Select((item, nestedIndex) => new {index, nestedIndex, item}))
.OrderBy(i => i.nestedIndex)
.ThenBy(i => i.index)
.Select(i => i.item)
.Take(10);
To explain why Zip alone is not enough: zip is equivalent to performing a join operation on the second collection to the first, where the
attribute to join by is the index. Therefore Only items that exist in the first collection, if they have a match in the second, will appear in the result.
The next option is to think about left join which will return all items of the first collection with a match (if exists) in the second. In the case described OP is looking for the functionality of a full outer join - get all items of both collection and match when possible.
I know you asked for LINQ, but I do often feel that LINQ is a hammer and as soon as a developer finds it, every problem is a nail. I wouldn't have done this one with LINQ, for a readability/maintainability point of view because I think something like this is simpler and easier to understand/more self documenting:
List<int> r = new List<int>(10);
for(int i = 0; i < 10; i++){
if(i < a.Count)
r.Add(a[i]);
if(i < b.Count)
r.Add(b[i]);
}
You don't need to stop the loop early if a and b collectively only have eg 8 items, but you could by extending the test of the for loop
I also think this case may be more performant than LINQ because it's doing a lot less
If your mandate to use LINQ is academic (this is a homework that must use LINQ) then go ahead, but if it's a normal everyday system that some other poor sucker will have to maintain one day, I implore you to consider whether this is a good application for LINQ
This will handle 2 or more internal List<List<int>>'s - it returns an IEnumerable<int> via yield so you have to call .ToList() on it to make it a list. Linq.Any is used for the break criteria.
Will throw on any list being null. Add checks to your liking.
static IEnumerable<int> FlattenZip (List<List<int>> ienum, int maxLength = int.MaxValue)
{
int done = 0;
int index = 0;
int yielded = 0;
while (yielded <= maxLength && ienum.Any (list => index < list.Count))
foreach (var l in ienum)
{
done++;
if (index < l.Count)
{
// this list is big enough, we will take one out
yielded++;
yield return l[index];
}
if (yielded > maxLength)
break; // we are done
if (done % (ienum.Count) == 0)
index += 1; // checked all lists, advancing index
}
}
public static void Main ()
{
// other testcases to consider:
// in total too few elememts
// one list empty (but not null)
// too many lists (11 for 10 elements)
var l1 = new List<int> { 1, 2, 3, 4 };
var l2 = new List<int> { 11, 12, 13, 14, 15, 16 };
var l3 = new List<int> { 21, 22, 23, 24, 25, 26 };
var l = new List<List<int>> { l1, l2, l3 };
var zipped = FlattenZip (l, 10);
Console.WriteLine (string.Join (", ", zipped));
Console.ReadLine ();
}

LINQ: Compare two lists and count subset

I am comparing 2 lists and I need to collect occurrences of a subset (modulesToDelete) from the master list (allModules) ONLY when MORE than one occurrence is found. (allModules contains modulesToDelete). Multiple occurrences of any module in modulesToDelete means those modules are being shared. One occurrence of a module in modulesToDelete means that module is isolated and is safe to delete (it just found itself). I can do this with nested foreach loops but this is as far as I got with a LINQ expression (which doesn't work)collect:
List<Module> modulesToDelete = { A, B, C, K }
List<string> allModules = {R, A, B, C, K, D, G, T, B, K } // need to flag B and K
var mods = from mod in modulesToDelete
where allModules.Any(name => name.Contains(mod.Name) && mod.Name.Count() > 1)
select mod;
here is my nested foreach loops which I want to replace with a LINQ expression:
foreach (Module mod in modulesToDelete)
{
int count = 0;
foreach (string modInAllMods in allModules)
{
if (modInAllMods == mod.Name)
{
count++;
}
}
if (count > 1)
{
m_moduleMarkedForKeep.Add(mod);
}
else if( count == 1)
{
// Delete the linked modules
}
}
You can use a lookup which is similar to a dictionary but allows multiple equal keys and returns an IEnumerable<T> as value.
var nameLookup = modulesToDelete.ToLookup(m => m.Name);
var safeToDelete = modulesToDelete.Where(m => nameLookup[m.Name].Count() == 1);
var sharedModules = modulesToDelete.Where(m => nameLookup[m.Name].Count() > 1);
Edit: However, i don't see how allModules is related at all.
Probably easier and with the desired result on your sample data:
var mods = modulesToDelete.Where(m => allModules.Count(s => s == m.Name) > 1);
One way of going about solving this will be to use Intersect function,
Intersection of two string array (ignore case)

Apply lambda expression for specific indices in list c#

I am new to lambda expression and I have problem to convert parts of code which involves indices of list inside the loop to equivalent lambda expression.
Example 1: Working with different indices inside one list
List<double> newList = new List<double>();
for (int i = 0; i < list.Count - 1; ++i)
{
newList.Add(list[i] / list[i + 1]);
}
Example 2: Working with indices from two lists
double result = 0;
for (int i = 0; i < list1.Count; ++i)
{
result += f(list1[i]) * g(list2[i]);
}
How to write equivalent lambda expressions?
A lambda expression is something that looks like {params} => {body}, where the characteristic symbol is the => "maps to." What you are asking for are typically referred to as LINQ query expressions, which come in two styles:
The functional style of query is typically a sequence of chained calls to LINQ extension methods such as Select, Where, Take, or ToList. This is the style I have used in the examples below and is also the much-more prevalent style (in my experience).
The "language integrated" style (*) uses built-in C# keywords that the compiler will turn into the functional style for you. For example:
var query = from employee in employeeList
where employee.ManagerId == 17
select employee.Name;
| compiler
v rewrite
var query = employeeList
.Where(employee => employee.ManagerId == 17)
.Select(employee => employee.Name);
Example 1:
var newList = Enumerable.Range(0, list.Count - 1)
.Select(i => list[i] / list[i + 1])
.ToList();
Example 2:
var result = Enumerable.Zip(list1.Select(f), list2.Select(g), (a, b) => a * b).Sum();
(*) I'm not actually sure this is the official name for it. Please correct me with the proper name if you know it.
For your first example you can try using Zip and Skip:
var result = list.Zip(list.Skip(1), (x, y) => x / y);
How does it work
If your initial list is {1, 2, 3}, then Skip(1) would result in {2, 3}; then Zip takes {1, 2, 3} and {2, 3} as inputs, and tells that, for each pair of numbers, it shall divide them. Repeat until there are no more elements in at least one list, and return the result as IEnumerable.
For the second example,
var result = list1.Zip(list2, (x, y) => f(x) * f(y)).Sum();

Elegant way to retrieve the index of the max element from a List in C#

I am discovering the tools C# provides to work with collections.
Suppose I have a List of elements, and I want to retrieve the one that most satisfies a property. Basically a elements.Max(predicate), except that I am interested in the index of the best element. The reason I want the index and not the element itself is there might not be such element, and the type is non-nullable.
Writing a function doing this is trivial, but I am interested in using the expressiveness of the tools C# provides to get a solution that is both concise, clear, and optimal (O(n)).
At this point I have the following code, which still looks cluttered, and evaluates the property twice.
List<foo> elements;
private int getBest(object x)
{
var indices = Enumerable.Range(0, elements.Count);
return indices.Aggregate(-1, (best, next) =>
(-1 == best || eval(x, elements[next]) > eval(x, elements[best])) ? next : best);
}
How can I make this piece of code better?
Addendum: I didn't put it in the code for the sake of clarity, but if eval() is below a certain threshold the element is discarded.
I'd recommend using the Select in conjunction with Aggregate LINQ extension methods. Using the Select method you can create an anonymous type which houses the index and value of each item within your collection. Then using the LINQ Aggregate method, you can narrow down the item with the greatest value. Some like this should work I think:
private int GetIndexOfHighestValue(IEnumerable<int> list)
{
return list.Select((i, v) => new { Index = i, Value = v })
.Aggregate((a, b) => (a.Value > b.Value) ? a : b)
.Index;
}
Doing it with LINQ is fun, but doing it without LINQ makes it more intuitive:
int bestIndex = -1;
int bestResult = -1;
for(int i = 0; i < elements.Count; ++i)
{
int currentResult = eval(x, elements[i]);
if (currentResult > bestResult)
{
bestResult = currentResult;
bestIndex = i;
}
}
Something like this could work:
// OOPS: This won't work because Max is defined the way it is. Always bugged me...
var result = elements.Select((e, i) => new {Element = e, Index = i}).Max(x => x.Element).Select(x => x.Index);
oh rats. Right. This will not work. So: Let's pull out our allrounder: Aggregate. Here we go:
var elements = new List<int>{1, 7, 2, 5};
var result = elements.Select((e, i) => new {Element = e, Index = i})
.Aggregate(
new { Element = elements.First(), Index = -1}, // gotta start somewhere and Element is non-nullable according to OP
(max, next) => (max.Element > next.Element) && max.Index >= 0 ? max : next,
max => max.Index);
This results in 1. Did that help?

Hacker News style ordering algorithm in Linq-To-SQL

According to this site the ordering algorithm for hacker news goes something like this:
(p - 1) / (t + 2)^1.5
Description:
Votes divided by age factor
p = votes (points) from users. t =
time since submission in hours.
p is subtracted by 1 to negate
submitters vote. age factor is (time
since submission in hours plus two) to
the power of 1.5.
Given a table structure similar to this:
Item
ID
Link
DatePosted
Item_Votes
ItemID
Value
What would be the best way to implement the algorithm using linq to sql, would I be able to write the query entirely in linq or would I need to use a stored procedure or something else.
Update. Ended up using the code below based off TJB's answer:
var votesQuery =
from i in db.Items
join v in db.Item_Votes on i.ItemID equals v.ItemID
orderby
(double)(v.Value - 1) /
Math.Pow(
(DateTime.Now - i.DatePosted.Value).TotalHours + 2,
1.5) descending
select i;
Using 2 1 Linq queries (there's probably still a more efficent way)
var votesQuery =
from i in items
join v in votes on i.Id equals v.ItemId
orderby
(v.Value - 1) /
Math.Pow(
(DateTime.Now - i.Posted).Add(new TimeSpan(2,0,0)).Hours,
1.5 )
select new
{
Item = i,
Vote = v
};
Use a Comparer. This will allow you to write the logic for the comparisons between rows any way you want.
Here is an example, using case-insensitive ordering:
public void LinqExample()
{
string[] words = {
"aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry"
};
var sortedWords = words.OrderBy(a => a, new CaseInsensitiveComparer());
ObjectDumper.Write(sortedWords);
}
public class CaseInsensitiveComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}
http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx
This might work (untested):
var orderedList =
from extracted in (
from i in unorderedList
select new
{
Item = i,
Order = (p - 1) / Math.Pow(t + 2, 1.5)
}
orderby extracted.Order
select extracted.Item
).ToList();

Categories