Related
I have two lists of Integer values:
List<int> list1 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> list2 = new List<int>() { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
I want to zip the above two lists so that the elements in even index are obtained from the sum of corresponding elements in List 1 and List 2 and the odd elements are obtained by multiplying them, I tried to do something like this but it did't work:
list1.Zip(list2, index => index % 2 == 0 ? (a, b) => a + b : (a, b) => a * b );
desired output
{ 12,24,16,56,20,96,24,144,28,200 }
You can Zip first then use the overload of Select that includes the index.
var result = list1.Zip(list2, (a,b) => (A:a, B:b))
.Select((x, i) => i % 2 == 0 ? x.A + x.B : x.A * x.B);
Note I'm using value tuples here, so depending on your version of C# you might need to use anonymous classes instead (a,b) => new { A=a, B=b }
Zip method doesn't have overload which supports index, you can use MoreLinq library or Select method instead (with element selector, which supports index)
var result = list1.Select(
(value, index) =>
index % 2 == 0 ? value + list2[index] : value * list2[index])
.ToList();
result.ForEach(Console.WriteLine);
It'll work if both lists have the same length and give you an expected output 12, 24, 16, 56, 20, 96, 24, 144, 28, 200
Another option is to Zip both lists into list of anonymous objects, then calculate the sum against them
var result = list1
.Zip(list2, (a, b) => new { a, b })
.Select((value, index) => index % 2 == 0 ? value.a + value.b : value.a * value.b)
.ToList();
Use .Select() instead of Zip
var result = list1.Select((e, i) =>
i % 2 == 0 ? e + list2[i] : e * list2[i])
.ToList()
Another option:
int index = 0;
var zipped = list1.Zip(list2, (a, b) => index++ % 2 == 0 ? a + b : a * b);
Succinctly, but it uses a side effect, which is of course bad.
I am not able to sort out this particular problem.
Given the sequence:
1 1 2 2 3 3 4 1 1 5 6 7 1 1
I want consecutive occurrence of 1's to be replaced by a single occurrence of 1.
1 2 2 3 3 4 1 5 6 7 1
I tried using DistinctUntilChanged but that did not work.
List<int> intList = new List<int>() { 1, 1, 2, 2, 3, 3, 4, 1, 1, 5, 6, 7, 1, 1 };
IObservable<int> intObsrvr = intList.ToObservable();
intObsrvr
.DistinctUntilChanged(x => x == 1)
.SubscribeConsole();
Output I got was:
1,2,1,5,1
I am also curious about how does this keySelector thing works as I cannot explain the output sequence I have got here.
Try this:
var intList = new List<int>() { 1, 1, 2, 2, 3, 3, 4, 1, 1, 5, 6, 7, 1, 1 };
var intObsrvr = intList.ToObservable();
var query =
intObsrvr
.Scan(
new { skip = false, value = int.MinValue },
(a, x) => new { skip = (a.value == 1) && (x == 1) , value = x })
.Where(x => !x.skip)
.Select(x => x.value);
I feel that .Scan is very undervalued.
You can also use .Publish/Zip/SelectMany:
var query =
intObsrvr.Publish(
xs => xs
.StartWith(int.MinValue)
.Zip(xs, (z, x) => z == 1 & x == 1 ? new int[] { } : new [] { x })
.SelectMany(x => x));
Take your pick.
var query =
intObsrvr.Publish(
xs => xs
.StartWith(int.MinValue)
.Zip(xs, (z, x) => z == 1 & x == 1
? Observable.Empty<int>()
: Observable.Return(x))
.SelectMany(x => x));
Even more options.
Another Zip variant without SelectMany:
var observable = new List<int> { 1, 1, 2, 2, 3, 3, 4, 1, 1, 5, 6, 7, 1, 1 }
.ToObservable();
observable.StartWith(int.MinValue).Zip(observable, (previous, current) => (previous, current))
.Where(t => t.current != 1 || t.current != t.previous)
.Select(t => t.current);
You can always create your own method if inbuilt ones don't match your requirements.
A DistinctUntilChanged that meets your needs is rather straightforward:
public static IEnumerable<T> DistinctUntilChanged<T>(
this IEnumerable<T> source)
{
using (var e = source.GetEnumerator())
{
if (!e.MoveNext())
yield break;
yield return e.Current;
var previous = e.Current;
while (e.MoveNext())
{
if (!e.Current.Equals(previous))
{
yield return e.Current;
previous = e.Current;
}
}
}
}
Here is another implementation:
/// <summary>Replaces repeated contiguous occurrences of a specific value
/// with a single occurrence of this value.</summary>
public static IObservable<TSource> DistinctUntilChanged<TSource>(
this IObservable<TSource> source, TSource value)
{
var comparer = EqualityComparer<TSource>.Default;
return source
.Select((v, i) => (Value: v, Index: i))
.DistinctUntilChanged(e => comparer.Equals(e.Value, value) ? -1 : e.Index)
.Select(entry => entry.Value);
}
This implementation assumes that the sequence has less than 2,147,483,647 elements, otherwise it will fail with an OverflowException. That's because it compares the indices instead of the values, and the type of the index is Int32.
suppose I have an array
int[] nums = new int[]{2, 4, 5, 7, 9, 8}
How do I use the delegate with the lambda expression to sum up the odd number in the array? I can do that with a for loop with a condition to check whether the number is odd and sum them up easily. Just wondering if there's any way to make the code shorter with delegate and lambda expression.
Thanks
var nums = new int[] {1, 2, 3, 4, 5};
var sum = nums.Sum(delegate(int i) { return i % 2 == 0 ? 0 : i; });
I believe this is what your asking for. Unless you want to create the delegate method outside of the lambda section in which case you could do something like this:
var nums = new int[] {1, 2, 3, 4, 5};
var del = new Func<int,int>((i) => i % 2 == 0 ? 0 : i);
var sum = nums.Sum(i => del(i));
Use LINQ's Sum() and check whether the current number is odd:
var oddsSum = nums.Sum(x => x % 2 * x);
or more verbose using Where() filtering:
var oddsSum = nums.Where(x => x % 2 == 1).Sum();
Lets say i have array of ints:
int[] values = new int[]{1,2,7,9,8,0};
How to OrderBy last 2 values?
int[] values = new int[]{1,2,7,9,0,8};
You can do it like this:
int[] values = new int[] { 1, 2, 7, 9, 8, 0 };
// Array.Sort accepts index and length, so you can sort only part of array
Array.Sort(values, values.Length - 2, 2);
// results in {1, 2, 7, 9, 0, 8}
Using the Generic Enumerable extensions, I came up with this. Don't think its the prettiest thing. Evk's solution looks much cleaner.
values = values.TakeWhile((n, index) => index < values.Length -2)
.Concat(
values.SkipWhile((n, index) => index < values.Length - 2).OrderBy(value => value)
).ToArray();
Try this
int[] values = new int[]{1,2,7,9,8,0};
var temp = values. Length > 1 ? new int[2] { values[length -2],values[values. Length-1] } : new inte[];
Var templist = values.tolist();
IF (values.length >1)
{
templist.removeat(values. Length-1)
templist.removeat(values.length-1)
}
templist.addrange(temp.tolist().orderby(x=> x))
Values= templist. Toarray()
Im writing from my mobile sorry for the unformated text
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);