I have a list of List<Tuple<string[], double[]>>
List<Tuple<string[], double[]>> tt = new List<Tuple<string[], double[]>>();
var t1 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 2, 3, 0 });
var t2 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 0, 3, 1 });
var t3 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 2, 1, 0 });
tt.Add(t1);
tt.Add(t2);
tt.Add(t3);
Lets say I want to divide each element in the double[] by the total counts non-zero counts in the columns. I would get the following results
t1 2/2, 3/3 0/1
t2 0/2, 3/3 1/1
t3 2/2, 1/3 0/1
Here is what I tried but it counts the row totals instead of the columns
var XX = (from tuples in tt
let rows = tuples.Item2.ToArray()
let result = rows.Select(x => x/rows.Count(i => i != 0)).ToArray()
select new Tuple<string[], double[]>(tuples.Item1, result)
).ToList();
What you are trying to do can be achieved with the following LINQ query:
List<Tuple<string[], double[]>> result = tt.Select(x =>
Tuple.Create(
x.Item1,
x.Item2.Select((y, i) => y / tt.Count(z => z.Item2[i] > 0))
.ToArray())).ToList();
Here are the resultant doubles printed to console:
Related
Input (pseudocode):
var array1=[1,2,3,4];
var array2=[5,6,7,8];
Result (pseudocode):
var output={[1,5],[2,6],[3,7],[4,8]};
You can use LINQ's Zip method:
var output = array1.Zip(array2, (a, b) => new [] { a, b });
If you need it as a List<int> or int[], you can materialise it with .ToList() or .ToArray() respectively.
Try it online
One more approach is to use linq Select EX:
int [] array1 =new [] { 1, 2, 3, 4 };
int [] array2 = new[] { 5, 6, 7, 8 };
var array3 = array1.Select((x, index) => new int[] { x, array2[index] }).ToArray();
I have two lists:
list1 = [a,b,c,4]
list2 = [1,23,5,6]
Now I need to create an anonymous object using linq lambda.
Something like.
list1 = DataTable.AsEnumerable().toList();
list2 = DataTable.AsEnumerable().toList();
var result = list1.Where(x => x.Field<int>(1) == 2018).Select(x => new[] {
new {x = "XYZ", y = x[0], z = list2[0]},
....}
}
How do I go about doing this?
You need Zip Linq method, consider this example:
int[] list1 = {1, 2, 3};
string[] list2 = {"a", "b", "c"};
var result = list1.Zip(list2, (i, s) => new {y = i, z = i});
Your code is fine, it just needs some small fixes:
string [] list1 = { "a", "b", "c", "4" };
int[] list2 = { 1, 23, 5, 6 };
object[] list3 = { "test", DateTime.Now, 56 };
var result = list1.Where(x => x == "a").Select(x =>
new { x = "XYZ", y = x[0], z = list2[0], t = list3[1] }).ToList();
The current problem is that the code works, but it gets exponentially slower as more combinations are passed in. (The calculation takes > 5 seconds after 15 combinations are passed in.) I need to be able to pass in up to 100 combinations and still get a result back that takes less than 2 seconds.
I'm betting that a Linq query could solve this?
What I want to achieve:
{1, 2, 3} + {1, 5, 26, 40} = 12 combinations:
[1,1]
[1,5]
[1,26]
[1,40]
[2,1]
[2,5]
[2,26]
[2,40]
[3,1]
[3,5]
[3,26]
[3,40]
However, this example above only includes 2 combination sets. I should be able to pass in any number of combination sets.
The closest thing that looks like it is similar to what I want as an end result, due to being fast and efficient, is a linq query that handles most or all of the logic within it. Example: Getting all possible combinations from a list of numbers
public IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Example of working code:
[Test]
public void StackOverflowExample_Simple()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 1, 5, 26, 40 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2 };
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(12, results.Count());
StringBuilder sb = new StringBuilder();
foreach (var result in results)
{
foreach (var number in result.OrderBy(x => x))
{
sb.Append(number + ",");
}
sb.Append("|");
}
string finalResult = sb.ToString().Replace(",|", "|");
Assert.AreEqual(finalResult, "1,1|1,5|1,26|1,40|1,2|2,5|2,26|2,40|1,3|3,5|3,26|3,40|");
}
[Test]
public void StackOverflowExample_TakesALongTime()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 4, 5 };
var list3 = new List<int>() { 1, 6 };
var list4 = new List<int>() { 2, 5 };
var list5 = new List<int>() { 1, 3, 55, 56 };
var list6 = new List<int>() { 3, 4, 7, 8, 9 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2, list3, list4, list5, list1, list1, list1, list3, list4, list4, list5, list6, list6, list2 };
DateTime startTime = DateTime.Now;
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(4147200, results.Count());
var duration = DateTime.Now.Subtract(startTime).TotalSeconds;
//duration = about 4 or 5 seconds
Assert.Less(duration, 10); //easy place to put a breakpoint
}
public IEnumerable<IEnumerable<int>> GetAllPossibleCombinations(List<List<int>> combinationSets)
{
List<List<int>> returnList = new List<List<int>>();
_RecursiveGetMoreCombinations(
ref returnList,
new List<int>(),
combinationSets,
0);
return returnList;
}
private void _RecursiveGetMoreCombinations(
ref List<List<int>> returnList,
List<int> appendedList,
List<List<int>> combinationSets,
int index)
{
var combinationSet = combinationSets[index];
foreach (var number in combinationSet)
{
List<int> newList = appendedList.AsEnumerable().ToList();
newList.Add(number);
if (combinationSets.Count() == index + 1)
{
returnList.Add(newList);
}
else
{
_RecursiveGetMoreCombinations(
ref returnList,
newList,
combinationSets,
index + 1);
}
}
}
Can you not just do permutations of the first and third sets (the OR sets) and then place '45' (the AND set), or whatever the static numbers are, in between those numbers?
You don't need to include 4 and 5 (in this example) in the permutation logic if they are always going to be present.
I have two sorted lists as below:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
I want the output to be: {1, 1, 2}
How to do this in C#?
Is there a way using Linq?
Use Intersect:
var commonElements = list1.Intersect(list2).ToList();
The extra 1 means you can't use Intersect because it returns a set.
Here's some code that does what you need:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var grouped1 =
from n in list1
group n by n
into g
select new {g.Key, Count = g.Count()};
var grouped2 =
from n in list2
group n by n
into g
select new {g.Key, Count = g.Count()};
var joined =
from b in grouped2
join a in grouped1 on b.Key equals a.Key
select new {b.Key, Count = Math.Min(b.Count, a.Count)};
var result = joined.SelectMany(a => Enumerable.Repeat(a.Key, a.Count));
CollectionAssert.AreEquivalent(new[] {1, 1, 2}, result);
This works nicely:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var lookup1 = list1.ToLookup(x => x);
var lookup2 = list2.ToLookup(x => x);
var results = lookup1.SelectMany(l1s => lookup2[l1s.Key].Zip(l1s, (l2, l1) => l1));
While both #Austin Salonen's solution and #Enigmativity's solution work for any given lists, neither take advantage of OP's condition that the lists are sorted.
Given that both lists will be ordered we can do a search in O(n + m) time where n and m are the length of each list. Not entirely sure what the previous solutions big o performance is, but it's definitely slower then O(n + m).
Basically we just walk both lists, moving one or both enumerators based on a comparison check.
var results = new List<int>();
var e1 = list1.GetEnumerator();
var e2 = list2.GetEnumerator();
var hasNext = e1.MoveNext() && e2.MoveNext();
while (hasNext) {
var value1 = e1.Current;
var value2 = e2.Current;
if (value1 == value2) {
results.Add(value1);
hasNext = e1.MoveNext() && e2.MoveNext();
} else if (value1 < value2) {
hasNext = e1.MoveNext();
} else if (value1 > value2) {
hasNext = e2.MoveNext();
}
}
That's it! results will be an empty list if no matches are found.
Note this assumes both lists are in ascending order. If it's descending, just flip the < and > operators.
I am late in answering this question, this might help future visitors.
List<int> p = new List<int> { 1, 1, 1, 2, 3 };
List<int> q = new List<int> { 1, 1, 2, 2, 4 };
List<int> x = new List<int>();
for (int i = 0; i < p.Count; i++ )
{
if (p[i] == q[i])
{
x.Add(p[i]);
}
}
I have following Table with records for ActivityLog:
ID, UserId, Category, Created
1 11 DeAssigned 05/10/2012
2 11 LogIn 05/11/2012
3 20 Assigned 06/15/2012
4 11 Assigned 06/10/2012
5 20 DeAssigned 06/13/2012
6 20 Assigned 07/12/2012
7 11 DeAssigned 07/16/2012
8 20 Assigned 08/15/2012
...
now i want to query the Table to create same struct the same Result such as this:
var data = new[] {
new { Month = "05", Assigned = 14, DeAssigned = 5, LogIn=1 },
new { Month = "06", Assigned = 5, DeAssigned = 2, LogIn=0 },
new { Month = "07", Assigned = 50, DeAssigned = 8, LogIn=0 },
new { Month = "08", Assigned = 15, DeAssigned = 1, LogIn=0 }
};
what i have achieved:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by new { l.Created.Value.Month, l.Category }
into groups
orderby groups.Key.Month
select new
{
Month = groups.Key.Month,
Category = groups.Key.Category,
Count = groups.Count()
});
there is not optimal result but count all Activity's grouped by Month:
[0] {Month = 6, Category = Assigned, Count = 2}
[0] {Month = 6, Category = Designed, Count = 1}
[0] {Month = 6, Category = LogIn, Count = 1}
[0] {Month = 7, Category = Assigned, Count = 3}
How can i query my Table to Format my Result in "Horizontal Counted" format?
Or simplier:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by l.Created.Month into groups
orderby groups.Key ascending
select new
{
Month = groups.Key,
Assigned = groups.Where(g => g.Category == "Assigned").Count(),
Deassigned = groups.Where(g => g.Category == "DeAssigned").Count(),
LogIn = groups.Where(g => g.Category == "LogIn").Count()
});