How to do convert the following ino lambda expression(method syntax)? - c#

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var pairs =
from a in numbersA
from b in numbersB
where a < b
select new { a, b };

You could try something like this:
var pairs = numbersA.SelectMany(a => numbersB.Where(b => b>a)
.Select(b => new { a, b }));
Please see this .NET Fiddle
What does SelectMany ?
Projects each element of a sequence to an IEnumerable and flattens
the resulting sequences into one sequence.
So from the result of the SelectMany that would contain all the combinations between the current a and all the numbers in the numbersB array, which are greater than a, we select an anonymous type with two properties, a and b. Doing this for all the numbers in numbersA we get that we want.

Related

How to get index of all values of not sorted array based on lower value C#

I am currently working on a simulation system so i've an array like
int[] arr = {2,5,9,10,0, 4,1,5,3};
I want array of indexes of values based on lower and output result like
result = {4, 6, 0, 8, 1, 7, 2, 3};
I searched all over for almost 3 days i can't find.
In the 2nd array you want the indexes of the elements in the first array as sorted in ascending order.
You can use LINQ to do this
int[] arr = { 2, 5, 9, 10, 0, 4, 1, 5, 3 };
int[] result = arr.Select((x, i) => (x, i))
.OrderBy(t => t.x)
.Select(t => t.i)
.ToArray();
Here, we used an overload of Select that yields the index:
Select<TSource,TResult>(IEnumerable, Func<TSource,Int32,TResult>).
The first Select creates a ValueTuple.
The test
Console.WriteLine(String.Join(", ", result));
Yields the result:
4, 6, 0, 8, 5, 1, 7, 2, 3
Note that the number 5 appears twice in the input array. Therefore, the result is ambiguous. (Your expected result has only 8 indexes but the input array has a length of 9)
My full .NET 6.0 test code (Console App):
namespace CoreConsoleApp;
internal static class SortedArrayIndexes
{
public static void Test()
{
// Indexes 0 1 2 3 4 5 6 7 8
int[] arr = { 2, 5, 9, 10, 0, 4, 1, 5, 3 };
int[] result = arr.Select((x, i) => (x, i))
.OrderBy(t => t.x)
.Select(t => t.i)
.ToArray();
Console.WriteLine(String.Join(", ", result));
}
}
It is called in my Main method with:
SortedArrayIndexes.Test();
Console.ReadKey();
In case you are working with an older Framework or language version, you can also use the older System.Tuple Class
int[] result = arr.Select((x, i) => new Tuple<int, int>(x, i))
.OrderBy(t => t.Item1)
.Select(t => t.Item2)
.ToArray();
We can use the built-in Array.Sort() method. It has a second parameter that returns the sorted indices as well, but it requires us to make a new array with the indices (i.e. starts from 0 and ends at the length of the original array)
int[] arr = {2,5,9,10,0,4,1,5,3};
int[] indexArr = Enumerable.Range(0, arr.Length).ToArray();
Array.Sort(arr, indexArr);
Note that you will need to add using System.Linq; if you get an error that Enumerable doesn't exist.

How to combine two arrays with identical index I make a list?

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();

Append two or more array to a single master array

I am new to C# programming, I migrated from python. I want to append two or more array (exact number is not known , depends on db entry) into a single array
like the list.append method in python does. Here the code example of what I want to do
int[] a = {1,2,3};
int[] b = {4,5,6};
int[] c = {7,8,9};
int[] d;
I don't want to add all the arrays at a time. I need somewhat like this
// I know this not correct
d += a;
d += b;
d += c;
And this is the final result I want
d = {{1,2,3},{4,5,6},{7,8,9}};
it would be too easy for you guys but then I am just starting with c#.
Well, if you want a simple 1D array, try SelectMany:
int[] a = { 1, 2, 3 };
int[] b = { 4, 5, 6 };
int[] c = { 7, 8, 9 };
// d == {1, 2, 3, 4, 5, 6, 7, 8, 9}
int[] d = new[] { a, b, c } // initial jagged array
.SelectMany(item => item) // flattened
.ToArray(); // materialized as a array
if you want a jagged array (array of arrays)
// d == {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
// notice the declaration - int[][] - array of arrays of int
int[][] d = new[] { a, b, c };
In case you want to append arrays conditionally, not in one go, array is not a collection type to choose for d; List<int> or List<int[]> will serve better:
// 1d array emulation
List<int> d = new List<int>();
...
d.AddRange(a);
d.AddRange(b);
d.AddRange(c);
Or
// jagged array emulation
List<int[]> d = new List<int[]>();
...
d.Add(a); //d.Add(a.ToArray()); if you want a copy of a
d.Add(b);
d.Add(c);
It seems from your code that d is not a single-dimensional array, but it seems to be a jagged array (and array of arrays). If so, you can write this:
int[][] d = new int[][] { a, b, c };
If you instead want to concatenate all arrays to a new d, you can use:
int[] d = a.Concat(b).Concat(c).ToArray();
var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);
You can use Array.Copy. It copies a range of elements in one Array to another array. Reference
int[] a = {1,2,3};
int[] b = {4,5,6};
int[] c = {7,8,9};
int[] combined = new int[a.Length + b.Length + c.Length];
Array.Copy(a, combined, a.Length);
Array.Copy(b, 0, combined, a.Length, b.Length);
Array.Copy(c, 0, combined, a.Length, b.Length, c.Length);

How to Get the longest match found in number of sets, order is important

I need to find a way to return the longest match found in number of sets/lists (values returns only once) when the order of items is important.
the list is not cyclic.
A match is a sequence of values that exists in all the lists and maintains the same order of elements in all the lists.
e.g. 1:
List<int> list1 = new List<int> { 1, 2, 3, 4, 7, 9 };
List<int> list2 = new List<int> { 1, 2, 5, 6, 3, 4, 7, 9 };
List<int> list3 = new List<int> { 1, 2, 3, 6, 8, 9 };
List<int> list4 = new List<int> { 1, 2, 5, 6, 8, 9 };
result { 1, 2 }
e.g. 2:
List<int> list1 = new List<int> { 2, 3, 6, 8, 1, 18 };
List<int> list2 = new List<int> { 2, 3, 4, 6, 8, 1, 18, 19, 17, 14 };
List<int> list3 = new List<int> { 2, 5, 6, 8, 1, 18, 16, 13, 14 };
List<int> list4 = new List<int> { 2, 6, 8, 1, 18, 19, 17, 14 };
result { 6, 8, 1, 18 }
The match doesn't have to be found at the beginning or at the end and can be on any part of any list.
I hope that I explained my problem good enough :)
Thanks!
You can build a map from pairs of ints to a count of how many of the lists they appear adjacent in.
Pseudo-code:
For each list L {
For each adjacent pair (x, y) in L {
Counts[x, y] += 1
}
}
Now you can iterate through the first list (or the shortest list), and find the longest run such that each adjacent pair (x, y) in the run with Counts[x, y] showing that the pair appears in every list.
Pseudo-code:
run = []
best_run = []
For x in L[0] {
if len(run) is zero or Counts[run[len(run)-1], x] == number of lists {
run = run + x
} else {
run = [x]
}
if run is longer than best_run {
best_run = run
}
}
This works given the assumption in the question that no integer appears twice in the same list.
This algorithm runs in O(N) time, where N is the sum of the lengths of all the lists.
Here's my approach.
First I need a way to compare lists:
public class ListCompare<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> left, List<T> right)
{
return left.SequenceEqual(right);
}
public int GetHashCode(List<T> list)
{
return list.Aggregate(0, (a, t) => a ^ t.GetHashCode());
}
}
Next a method to produce all subsequences of a source list:
Func<List<int>, IEnumerable<List<int>>> subsequences = xs =>
from s in Enumerable.Range(0, xs.Count)
from t in Enumerable.Range(1, xs.Count - s)
select xs.Skip(s).Take(t).ToList();
Now I can create a list of lists:
var lists = new [] { list1, list2, list3, list4, };
Finally a query that pulls it all together:
var answer =
lists
.Skip(1)
.Aggregate(
subsequences(lists.First()),
(a, l) => a.Intersect(subsequences(l), new ListCompare<int>()))
.OrderByDescending(x => x.Count)
.FirstOrDefault();
Given the sample data provided in the question this produces the expected results.
First generate an ordered combination of int from the shortest list
Compare the lists other than shortest list with the combination. For easy comparison of lists I just convert to string and use string.Contains()
Return immediately if find the match as the items left are next order or the shorter one.
public static List<int> GetLongestMatch(params List<int>[] all)
{
var shortest = all.Where(i => i.Count == all.Select(j => j.Count).Min()).First();
var permutations = (from length in Enumerable.Range(1, shortest.Count)
orderby length descending
from count in Enumerable.Range(1, shortest.Count - length + 1)
select shortest.Skip(count - 1).Take(length).ToList())
.ToList();
Func<List<int>, string> stringfy = (list) => { return string.Join(",", list.Select(i => i.ToString()).ToArray()); };
foreach (var item in permutations)
{
Debug.WriteLine(string.Join(", ", item.Select(i => i.ToString()).ToArray()));
if (all.All(list => stringfy(list).Contains(stringfy(item))))
{
Debug.WriteLine("Matched, skip process and return");
return item;
}
}
return new List<int>();
}
Usage
var result = GetLongestMatch(list1, list2, list3, list4);
Result
2, 3, 6, 8, 1, 18
2, 3, 6, 8, 1
3, 6, 8, 1, 18
2, 3, 6, 8
3, 6, 8, 1
6, 8, 1, 18
Matched, skip process and return

Sort list based on multiple conditions

I have a list of integer lists, like that:
A -> 10 10 1 1 1
B -> 10 9 9 7 6
...
I would like to sort them based on how many 10s they have, then on how many 9s, 8s, 7s, and so on untile the 1s
So in the example above A should be better than B because even if it has less total points, it has two 10s instead of only 1.
Code should be generic because I don't know how many numbers will be available for each case (sometimes 10, sometimes 5, or even only 3).
I developed something like that:
lists.OrderByDescending(a => a.Where(b => b == 10).Count()).
ThenByDescending(a => a.Where(b => b == 9).Count()).
and so on, but this is not generic...
I hope the question is clear... thank you very much!
You can create query which orders lists by count of 10s, then compose query by adding additional orderings for numbers from 9 to 1:
var query = lists.OrderByDescending(l => l.Count(x => x == 10));
for (int i = 9; i >= 1; i--)
query = query.ThenByDescending(l => l.Count(x => x == i));
For these sample lists:
var lists = new[] {
new[] { 10, 9, 9, 8, 7 },
new[] { 10, 9, 9, 7, 6 },
new[] { 10, 10, 1, 1, 1 }
};
Result will be:
[10, 10, 1, 1, 1]
[10, 9, 9, 8, 7]
[10, 9, 9, 7, 6]
It's simple, but not very efficient. If you need better performance, then consider creating custom comparer. Here is sample with comparer which uses zipped ordered sequences to check if all items in sequences are same, or get first item which is different:
public class CustomComparer : Comparer<IList<int>>
{
public override int Compare(IList<int> x, IList<int> y)
{
var comparisons = x.Zip(y, (a,b) => a.CompareTo(b));
foreach(var comparison in comparisons)
{
if (comparison != 0)
return comparison;
}
return x.Count.CompareTo(y.Count);
}
}
NOTE: If items in lists are not ordered, then you should sort them before zipping:
var comparisons =
x.OrderByDescending(i => i)
.Zip(y.OrderByDescending(i => i), (a,b) => a.CompareTo(b));
It works very simple. Consider two lists:
[10, 9, 9, 8, 7, 5]
[10, 9, 9, 7, 6]
It will create pairs of items in corresponding positions:
{10,10}, {9,9}, {9,9}, {8,7}, {7,6}
Then items in each pair will be compared one by one, until first mismatch will be found:
0, 0, 0, 1 (four comparisons only)
That means first list has more 8s than second one. Usage:
var query = lists.OrderByDescending(i => i, new CustomComparer());
Result is same.
The following comparer
public class Comparer : IComparer<IEnumerable<int>>
{
public int Compare(IEnumerable<int> a, IEnumerable<int> b)
{
var aOrdered = a.OrderByDescending(i => i).Concat(new[] { int.MinValue });
var bOrdered = b.OrderByDescending(i => i).Concat(new[] { int.MinValue });
return a.Zip(b, (i, j) => i.CompareTo(j)).FirstOrDefault(c => c != 0);
}
}
lets you order you lists of lists like so
var result = lists.OrderByDescending(i => i, new Comparer());
without iterating through each list ten times counting individual elements.
This compares the lists and returns conventional comparison result - 1, 0, or -1 is returned depending on whether one value is greater than, equal to, or less than the other.
static int CompareLists(List<int> a, List<int> b)
{
var grpA = a.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
var grpB = b.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
for (int i = 10; i >= 0; i--)
{
int countA = grpA.ContainsKey(i) ? grpA[i] : 0;
int countB = grpB.ContainsKey(i) ? grpB[i] : 0;
int comparison = countA.CompareTo(countB);
if (comparison != 0)
return comparison;
}
return 0;
}
First we convert the lists into dictionary of number->amount of occurences.
Then we iterate through numbers from 10 to 0 and compare the number of occurences. If the result is 0, then we go to another number.
If you have List<List<int>> to sort, just use list.Sort(CompareLists) as in:
List<int> d = new List<int> { 10, 6, 6 };
List<int> b = new List<int> { 10, 9, 9 };
List<int> a = new List<int> { 10, 10, 1, 1, 1 };
List<int> c = new List<int> { 10, 7, 7 };
List<int> e = new List<int> { 9, 3, 7 };
List<int> f = new List<int> { 9, 9, 7 };
List<List<int>> list = new List<List<int>>() { a, b, c, d, e, f };
list.Sort(CompareLists);

Categories

Resources