So here a problem which i am facing -
I have two lists with following structure
public class Payment
{
public int Period { get; set; }
public decimal Balance{ get; set; }
}
I have created following two lists as below
List<Payment> A = new List<Payment>();
List<Payment> B = new List<Payment>();
The list looks like this.
List A List B
Perid Payment Perid Payment
1 10 1 16
2 12 2 13
3 45 3 44
4 23 4 33
5 36 5 34
6 45 6 35
I am trying to add these two Payments from list A,B and create a third list which should have same structure.
List C
Perid Payment
1 10+16
2 12+13
3 45+44
4 23+33
5 36+34
6 45+35
I understand with for looping its possible but is there anyway where Linq OR Lambda expressions can be used in simpler way?
Any help is deeply appreciated.
Try LINQ's Zip method. It helps you to iterate over two collections simultaneously.
Here's an example -
using System;
using System.Linq;
class Program
{
static void Main()
{
// Two source arrays.
var array1 = new int[] { 1, 2, 3, 4, 5 };
var array2 = new int[] { 6, 7, 8, 9, 10 };
// Add elements at each position together.
var zip = array1.Zip(array2, (a, b) => (a + b));
// Look at results.
foreach (var value in zip)
{
Console.WriteLine(value);
}
}
}
I think you shouldn't do it. Write the code in the old-fashioned way is going to be cleared to almost anybody reading the code.
More importantly, the non-LINQ code will allow you to add sanity checks in a reasonable fashion (for example, are you sure all periods in the first list exist in the second? And vice versa?).
If you want to get more modern, I suggest using a generator, something like this:
IEnumerable<Payment> UnitePayments(List<Payment> list1, List<Payment> list2)
{
... Check that list1 and list2 are the same length ...
for(int i=0; i<list1.Length; i++)
{
if(list1.Period!=list2.Period) ... handle this case...
yield return new Payment { Period = list1.Period,
Balance = list1.Balance + list2.Balance };
}
}
Your code readers will thank you.
You have two options as already suggested:-
Using Concat + GroupBy :-
List<Payment> result = A.Concat(B).GroupBy(x => x.Period)
.Select(x => new Payment
{
Period = x.Key,
Balance = x.Sum(z => z.Balance)
}).ToList();
Using Zip :-
List<Payment> result1 = A.Zip(B, (first, second) => new Payment
{
Period = first.Period,
Balance = first.Balance + second.Balance
}).ToList();
You can refer to this Fiddle.
// Try for loop i think it would be good way to handle this situation there is other LINQ queries but i believe this is easier..
List<int> a = new List<int>();
a.Add(1 ) ;
a.Add(2);
List<int> b = new List<int>();
b.Add(5) ;
b.Add(6);
List<int> c = new List<int>();
for (int x = 0; x < a.Count; x++)
{
c.Add(a[x] + b[x]);
Label1.Text += c[x] + "";
}
Related
This question already has answers here:
The Most frequent Number in an array
(11 answers)
How do I find duplicates in an array and display how many times they occurred?
(14 answers)
Closed 1 year ago.
I'm trying to know the number that is most present in one array.
Example:
8 4 3 8 4 4 1 5
In this case, I want the program to tell me the number is 4.
This is what I've written so far, but the console.Writeline returns an error system.32.
Can you help ?
int[] moda = new int[21];
for (int j = 0; j < avaliacoes.Length; j++)
{
int avaliacao = avaliacoes[j];
moda[avaliacao] = moda[avaliacao] + 1;
}
Console.WriteLine("\nA moda é{0}: ", moda);
Grouping with some ordering on group size should get the job done.
To summarize what I am doing I am grouping the array by there values, I then Emit that group into an anonymous type that will hold the key as well as the group count. Third I order by descending so we order or enumerable from high value to low, which will allow me to say the first element in the enumeration must be the top value (if not equal to the top value).
class Program
{
static void Main(string[] args)
{
var a = new[] { 8, 4, 3, 8, 4, 4, 1, 5 };
var mostPresent = a
.GroupBy(e => e)
.Select(e => new { Key = e.Key, Count = e.Count() })
.OrderByDescending(e => e.Count)
.FirstOrDefault();
Console.WriteLine(mostPresent);
}
}
There are many methods for doing that, here is one:
static void Main(string[] args)
{
// Create array
const int arrLength = 10;
int[] mainArray = new int[arrLength];
// Fill array with random numbers
Random randNum = new Random();
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = randNum.Next(10);
}
// Create a dictionary for counting
Dictionary<int, int> countDic = new Dictionary<int, int>();
foreach (var currentNumber in mainArray)
{
// If the current number has appeared before increase the count for that number
if (countDic.TryGetValue(currentNumber, out int _))
{
countDic[currentNumber]++;
}
// If it's first time current number has appeared set its count as one
else
{
countDic.Add(currentNumber, 1);
}
}
// Print frequency of numbers
foreach (var num in countDic)
{
Console.WriteLine($"{num.Key} appears {num.Value} times in the array!");
}
// Print the number which appears the most in the array
int maxNum = countDic.Aggregate((x, y) => x.Value > y.Value ? x : y).Key;
Console.WriteLine(maxNum);
Console.Read();
}
Ask me if there is anything that you can not understand in the solution
You can do that easily with LINQ. I'll explain what happens below:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
List<int> ints = new List<int> { 8, 4, 3, 8, 4, 4, 1, 5 };
var query = from i1 in ints
select new
{
number = i1,
count = ints.Where(i2 => i2 == i1).Count()
};
var most = query.OrderByDescending(x => x.count).First().number;
Console.WriteLine($"Number: {most}");
Console.ReadKey();
}
}
}
In the first query I iterate over all ints in the list and create an anonymous object with 2 properties 'number' and 'count'. The count contains the amount of ints in the list with the number of the first iteration.
In the second line the 'most'is selected by ordering the anonymous types in descending order on 'count' and taking the First item of that result. If you have more numbers in your array with the same number of entries you will get only the first one. So if '4' and 5' both are present 4 times it is not guaranteed which result you will get. It could be '4' but just as well '5'.
I have array of ints(Call him A) and IEnumarable(Call him B):
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
I need to count how many times exist each number from A inside B and sum the result.
For example:
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
result = 1+3+2+1+0
What is elegant way to implement it?
With LINQ it is easy:
int count = A
.Where(x => B.Contains(x))
.Count();
Counts how many times elements from A are contained in B.
As Yuval Itzchakov points out, this can be simplified like this:
int count = A.Count(x => B.Contains(x));
I need to count how many times exist each number from A inside B and sum the result.
You can get both the count and sum as follows
List<int> b = new List<int>() { 1,2,4,8,289 };
List<int> a = new List<int>() { 2,2,56,2,4,33,4,1,8 };
var subset = a.Where(i => b.Contains(i));
var count = subset.Count(); // 7
var sum = subset.Sum(); // 23
Note that I reuse the same Linq expression to get both the count and the sum.
One might be tempted to use a HashSet<int> in place of a List<int> because the .Contains operation is faster. However, HashSet is a set, meaning if the same number is added multiple times, only one copy of that number will remain in the set.
sweet and simple.. one line solution
why dont you try it..
int sum = 0;
A.ToList().ForEach(a=>sum +=B.Count(b=>b==a));
Console.Write(sum);
you can sweap the A/B it will still work
With Linq you can do like this
var B = new List<int>{ 1, 2, 4, 8, 289 };
var A = new List<int> { 2, 2, 56, 2, 4, 33, 4, 1, 8 };
var repetitionSum = B.Select(b => A.Count(a => a == b)).Sum(); //result = 7
And if you want, you can get the individual repetition list like this
var repetition = B.Select(b => A.Count(a => a == b)).ToList();
// { 1, 3, 2, 1, 0 }
It is not clear if you want to know the occurrences of each number or the final count (your text and your example code differ). Here is the code to get the number of appearances of each number
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int[] a = new []{1,2,3};
int[] b = new []{1,2,2,3};
Dictionary<int, int> aDictionary = a.ToDictionary(i=>i, i => 0);
foreach(int i in b)
{
if(aDictionary.ContainsKey(i))
{
aDictionary[i]++;
}
}
foreach(KeyValuePair<int, int> kvp in aDictionary)
{
Console.WriteLine(kvp.Key + ":" + kvp.Value);
}
}
}
I've got an interesting issue I'm trying to solve. My knowledge of Linq is honestly very shallow and I'm pretty certain this is the sort of problem that would be most elegantly solved with a Linq based solution but I've attempted a few things so far with what little knowledge I have to little success.
Here's the skinny: I have a List of decimal Lists and I want to find a combination from the lists adding up to a target decimal using only one element from each list. To clarify:
List<List<decimal>> parentList; // this is the main list I'm drawing from
List<decimal> childList { 1 , 2 , 3 , 4 , 5 }; // each list inside of the main list would look something like this
So if my parentList contains five of the childLists, I need to find a combination that only uses one item each list once. This doesn't mean I can't use the same value twice, if parentList[0] and parentList[1] both contain 3 and I'm adding to 6, {3,3} would be a valid solution. However, if parentList[0] were { 1 , 2 , 3 } and parentList[1] were { 4 }, the only valid solution to add to 6 woudl be {2 , 4}, since the second list doesn't contain 3.
I hope this all makes sense and I'm not asking too much. I don't mind just being oriented in the direction of a solution, a push in the right direction as opposed to the whole answer. Thanks!
As others has already stated, LINQ is not suitable for task like this. Such complex LINQ would not be good both from maintenance and performance perspective.
But I could not stop until I made my inner geek happy! You asked for it...
private static IEnumerable<IEnumerable<decimal>> FindCombinations(IEnumerable<IEnumerable<decimal>> listOfLists, decimal target)
{
return listOfLists.Aggregate(
Enumerable.Repeat(Enumerable.Empty<decimal>(), 1),
(acc, seq) =>
from accseq in acc
from item in seq
select accseq.Concat(new[] {item}))
.Where(x => x.Sum(y => y) == target);
}
And here is console test application:
private static void Main(string[] args)
{
var target = 12;
var listOfLists = new List<List<decimal>>()
{
new List<decimal> { 1, 2, 3 },
new List<decimal> { 3, 4, 5 },
new List<decimal> { 5, 6, 7 },
};
foreach (var combination in FindCombinations(listOfLists, target))
{
Console.WriteLine("{0} = {1}", string.Join(" + ", combination.Select(y => y.ToString(CultureInfo.InvariantCulture))), target);
}
Console.ReadKey();
}
Sounds like something you would solve using recursion and not Linq. Here is an example:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<List<decimal>> listOfLists = new List<List<decimal>>()
{
new List<decimal>() { 1, 2, 3 },
new List<decimal>() { 3, 4, 5 },
new List<decimal>() { 5, 6, 7 },
};
PrintAllCombinationsForTargetValue(listOfLists, 12);
}
private static void PrintAllCombinationsForTargetValue(List<List<decimal>> listOfLists, decimal targetValue)
{
Stack<decimal> currentCombination = new Stack<decimal>();
FindNextElement(listOfLists, targetValue, 0, 0, currentCombination);
}
private static void FindNextElement(List<List<decimal>> listOfLists, decimal targetValue, int listIndex, decimal trackingValue, Stack<decimal> currentCombination)
{
List<decimal> currentList = listOfLists[listIndex];
foreach (decimal currentValue in currentList)
{
decimal currentTrackingValue = trackingValue + currentValue;
currentCombination.Push(currentValue);
if (currentTrackingValue < targetValue && listIndex < listOfLists.Count - 1)
{
// There is still la chance that we can get what we want. Let's go to the next list.
FindNextElement(listOfLists, targetValue, listIndex + 1, currentTrackingValue, currentCombination);
}
else if (currentTrackingValue == targetValue && listIndex == listOfLists.Count - 1)
{
// Found a valid combination!
currentCombination.Reverse().ToList().ForEach(element => Console.Write(element + " "));
Console.WriteLine();
}
currentCombination.Pop();
}
}
}
}
You can achieve this with recursion. This will find one combination that sums up to the target, using one value from each list, or null if none exists.
public static List<decimal> CombinationSumMatches(
this IEnumerable<IEnumerable<decimal>> lists,
decimal target)
{
if (lists.Any())
{
var firstList = lists.First();
if (lists.Skip(1).Any())
{
foreach (var num in firstList)
{
var newTarget = target - num;
var subCombination = lists.Skip(1).CombinationSumMatches(newTarget);
if (subCombination != null)
{
subCombination.Insert(0, num);
return subCombination;
}
}
}
else
{
if (firstList.Contains(target))
{
return new List<decimal> { target };
}
}
}
return null;
}
This will first check if there are any lists. If there are then it looks at the first one and sees if there are more. If there are more it goes through each number of the first list and subtracts that value from the target and does a recursive call on the remaining lists. If there is a non null answer it inserts the number and returns. Now if there is only one list then it just checks the list for the target and returns a list with that target value if it finds it. If there are no lists, or only one without the target, or nothing that matches the sub combinations then it will just return null.
I m in a situation where i need to find record from a generic list using its position, means need to find 1st 5th and 9th record , then 2nd 6th and 10th record and so on...
Situation is
A list of projects assigned to a List of Team,
So if we have 20 projects and 4 teams
then 1st project go to 1st team, 2nd go to 2nd team , 3rd go to 3rd team, 4th go to 4th team
then again 5th project go to 1st team
so its like
Projects Team
1 1
2 2
3 3
4 4
5 1
6 2
7 3
8 4
9 1
.
.
so now i want to run a Query on Generic List to get record for each team, so for first team record 1,5 and 9.... need to fetch.
Some thing like
List<Project> lst = list (from Database)
//For 1stTeam
lst = lst.Index(1,5,9...);
//For 2nsTeam
lst = lst.Index(2,6,10...);
Hope i clear my point.
You could do something like this with LINQ Select and GroupBy:
List<int> list = new List<int>{1,2,3,4,5,6,7,8,9,10};
int numberOfTeams = 4;
var projectsByTeam = list
.Select((number, index) => new {Value = number, Index = index})
.GroupBy(item => item.Index % numberOfTeams)
.Select(item => new {TeamNumber = item.Key+1, ProjectIDs = item.Select(x => x.Value).ToList()})
.ToList();
Splits the original list into
{
{TeamNumber = 1, ProjectIDs = {1,5,9}},
{TeamNumber = 2, ProjectIDs = {2,6,10}},
{TeamNumber = 3, ProjectIDs = {3,7}},
{TeamNumber = 4, ProjectIDs = {4,8}},
}
First, this is not specific to generic lists.
You have to create a new list, and then, one by one, add the items from the original list that you want in the new list. You can access single items at a given position via the indexer (square brackets).
List<Project> lst = // list (from Database)
List<Project> firstTeam = new List<Project>();
firstTeam.Add(lst[1]);
firstTeam.Add(lst[5]);
firstTeam.Add(lst[9]);
List<Project> secondTeam = new List<Project>();
secondTeam.Add(lst[2]);
secondTeam.Add(lst[6]);
secondTeam.Add(lst[10]);
Of course, if the items are distributed that regularly throughout the original lst, you can automatically determine the items:
List<Project> firstTeam = new List<Project>();
for (int i = 1; i < lst.Count; i += 4) {
firstTeam.Add(lst[i]);
}
i.e. you loop over the original list, taking every 4th item.
If the items to add to one of the teams are not distributed regularly throughout lst, you will have to add them one by one, but you might be able to make use of the shorter list initializer syntax:
List<Project> firstTeam = new List<Project>() { lst[1], lst[5], lst[9] };
Lastly, note that List<T> starts counting indices at zero, so the very first item is lst[0], not lst[1].
You are looking for the params keyword. It will allow you to pass in to Index an array of arguments, which are the indexes in your case.
In your case an extension method can do the trick:
public static List<Project> Index(this List<Project> list, params int[] indexes)
{
var newList = new List<Project>();
foreach(var index in indexes)
{
newList.Add(list[index]);
}
return newList;
}
// Define other methods and classes here
static IEnumerable<IEnumerable<T>> CustomSplit<T>(this IEnumerable<T> source, int max)
{
var results = new List<List<T>>();
for (int i = 0; i < max; i++)
{
results.Add(new List<T>());
}
int index = 0;
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
int circularIndex = index % max;
results[circularIndex].Add(enumerator.Current);
index++;
}
}
return results;
}
And here is how to use it:
void Main()
{
var elements = Enumerable.Range(0, 100).CustomSplit(4);
}
You can use:
List<Project> projects; // = something from db
var neededIndexes = new[] { 0, 4, 8 };
var result = projects.Where((project, index) => neededIndexes.Contains(index)).ToList();
Or if the indexes are evenly distributed:
List<Project> projects; // = something from db
var result = projects.Where((project, index) => index % 4 == 0).ToList();
This solve your problem:
List for each team:
List<List<Project>> projectsPerTeam = new List<List<Project>> ();
for(int i=0;i<teamsList.Count();i++)
{
projectsPerTeam.Add(new List<Project> ());
}
Now your issue (add project for correct team):
for(int i=0;i<projectsList.Count();i++)
{
projectsPerTeam[i%teamList.Count()].Add(projectsList[i]);
}
I want to display a customer's accounting history in a DataGridView and I want to have a column that displays the running total for their balance. The old way I did this was by getting the data, looping through the data, and adding rows to the DataGridView one-by-one and calculating the running total at that time. Lame. I would much rather use LINQ to SQL, or LINQ if not possible with LINQ to SQL, to figure out the running totals so I can just set DataGridView.DataSource to my data.
This is a super-simplified example of what I'm shooting for. Say I have the following class.
class Item
{
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public decimal RunningTotal { get; set; }
}
I would like a L2S, or LINQ, statement that could generate results that look like this:
Date Amount RunningTotal
12-01-2009 5 5
12-02-2009 -5 0
12-02-2009 10 10
12-03-2009 5 15
12-04-2009 -15 0
Notice that there can be multiple items with the same date (12-02-2009). The results should be sorted by date before the running totals are calculated. I'm guessing this means I'll need two statements, one to get the data and sort it and a second to perform the running total calculation.
I was hoping Aggregate would do the trick, but it doesn't work like I was hoping. Or maybe I just couldn't figure it out.
This question seemed to be going after the same thing I wanted, but I don't see how the accepted/only answer solves my problem.
Any ideas on how to pull this off?
Edit
Combing the answers from Alex and DOK, this is what I ended up with:
decimal runningTotal = 0;
var results = FetchDataFromDatabase()
.OrderBy(item => item.Date)
.Select(item => new Item
{
Amount = item.Amount,
Date = item.Date,
RunningTotal = runningTotal += item.Amount
});
Using closures and anonymous method:
List<Item> myList = FetchDataFromDatabase();
decimal currentTotal = 0;
var query = myList
.OrderBy(i => i.Date)
.Select(i =>
{
currentTotal += i.Amount;
return new {
Date = i.Date,
Amount = i.Amount,
RunningTotal = currentTotal
};
}
);
foreach (var item in query)
{
//do with item
}
How about this: (credit goes to this source)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
delegate string CreateGroupingDelegate(int i);
static void Main(string[] args)
{
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 69, 2007};
int running_total = 0;
var result_set =
from x in list
select new
{
num = x,
running_total = (running_total = running_total + x)
};
foreach (var v in result_set)
{
Console.WriteLine( "list element: {0}, total so far: {1}",
v.num,
v.running_total);
}
Console.ReadLine();
}
}
}
In case this hasn't been answered yet, I have a solution that I have been using in my projects. This is pretty similar to an Oracle partitioned group. The key is to have the where clause in the running total match the orig list, then group it by date.
var itemList = GetItemsFromDBYadaYadaYada();
var withRuningTotals = from i in itemList
select new {i.Date, i.Amount,
RunningTotal = itemList.Where( x=> x.Date == i.Date).
GroupBy(x=> x.Date).
Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single()};
Aggregate can be used to obtain a running total as well:
var src = new [] { 1, 4, 3, 2 };
var running = src.Aggregate(new List<int>(), (a, i) => {
a.Add(a.Count == 0 ? i : a.Last() + i);
return a;
});
Most of the other answers to this, which properly set the running totals within the objects, rely on a side-effect variable, which is not in the spirit of functional coding and the likes of .Aggregate(). This solution eliminates the side-effect variable.
(NB - This solution will run on the client as with other answers, and so may not be optimal for what you require.)
var results = FetchDataFromDatabase()
.OrderBy(item => item.Date)
.Aggregate(new List<Item>(), (list, i) =>
{
var item = new Item
{
Amount = i.Amount,
Date = i.Date,
RunningTotal = i.Amount + (list.LastOrDefault()?.RunningTotal ?? 0)
};
return list.Append(item).ToList();
// Or, possibly more efficient:
// list.Add(item);
// return list;
});
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<int>{1, 5, 4, 6, 8, 11, 3, 12};
int running_total = 0;
list.ForEach(x=> Console.WriteLine(running_total = x+running_total));
}
}