Linq - Get the Index of the Last Non-Zero Number of Array - c#

Is there a Linq expression that returns the index of the last non-zero value in an array? I'm not interested in an extension, only a simple linq expression.
I'm imagining something like this pseudo code:
int index = {0, 2, 1}.LastOrDefaultAt(i => i > 0);
The returned value should be 2;

You can use the Array.FindLastIndex<T> method for this:
int index = Array.FindLastIndex(myIntArray, item => item > 0);
I notice that you mention "non-zero" rather than "greater than zero" in your question text. Should your predicate be: item => item != 0 ?

List<T> has an extension method for this called FindLastIndex
var index = new int[] { 0, 2, 1}.ToList().FindLastIndex(x => x > 0);

class Program
{
static void Main(string[] args)
{
int[] index = { 0, 2, 1 };
var query = from p in index
where p != 0
orderby p descending
select p;
Console.WriteLine(query.FirstOrDefault());
Console.ReadKey();
}
}
Output: 2. Could be written in method syntax if desired:
var index = new int[] { 0, 2, 1 }.Where(a => a != 0).OrderByDescending(a => a).FirstOrDefault();

Related

CS7036 C# in Array.FindAll + Lambda

I want to change A to B.
A is
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = new List<int>();
foreach ( var item in list )
{
if (item % 2 == 0)
{
evenList.Add(item);
}
}
foreach ( var item in evenList )
{
Console.Write(item + ",");
}
and B is
List<int> evenList = list.FindAll((elem) => elem % 2 == 0);
evenList.ForEach(elem) => { Console.Write(elem + ","); } );
but at B, I faced an Error like this:
CS7036 C# There is no argument given that corresponds to the required
formal parameter 'match' of 'Array.FindAll<T>(T[], Predicate<T>)'
ps. I added using
using System;
using System.Collections.Generic;
Is there anything that I forgot?
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = Array.FindAll(list, elem => elem % 2 == 0).ToList();
evenList.ForEach(elem => { Console.Write(elem + ","); } );
Array.FindAll is not extension method, so you simply can't call list.FindAll()
Array do not have ForEach, so you need to cast evenList ToList()
That's because Array.FindAll is static, so you should call it like this:
var NewList = Array.FindAll(list, (elem) => elem %2 == 0);
From MSDN:
Syntax:
public static T[] FindAll<T>(
T[] array,
Predicate<T> match
)
link: https://msdn.microsoft.com/en-us/library/1kkxfxdd(v=vs.110).aspx
Cheers
EDIT:
Programming is not a guessing game where you try to write code without respecting the proper syntax.
Here's what you should be doing:
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = Array.FindAll(list, elem => elem % 2 == 0).ToList();
Console.Write(string.Join(",", evenList) );
Any reason why you aren't using Linq? It is newer and applies to any type of collection, not just int[].
using System.Linq;
Console.Write(list
.Where(i => i % 2 == 0)
.Select(i => i.ToString())
.DefaultIfEmpty()
.Aggregate((a, b) => a + "," + b));
Performancewise, this will execute at the same complexity as your for loop, but it will likely be slightly slower overall (though I actually think it won't be that much slower). Linq evaluates lazily which helps here.

How to find a one dimensional array in a two dimensional array in C#

I have a two dimensional array namely States. I create a one dimensional array, say SubState. Then I change SubState. I want to find new SubState in States and get the index. As an example:
int[][] States = new int[3][] { new int[] { 3, 3, 4 }, new int[] { 2, 5, 1 }, new int[] { 2, 3, 4 } };
int[] SubState = new int[States[0].Length];
States[0].CopyTo(SubState, 0);
SubState[0] -= 1;
I want to find the index of new SubState in State, which will be 2 in the example.
Thanks.
You're looking for SequenceEqual:
int index = -1;
for (int i = 0; i < States.Length; i++)
if (States[i].SequenceEqual(SubState))
{
index = i;
break;
}
If you define a LINQ FindIndex operator, you can express it more concisely using:
int index = States.FindIndex(s => s.SequenceEqual(SubState));
You can use SequenceEqual method inside a LINQ query, like this:
var nextStateIndex = States
.Select((a, i) => new {Index = i, Array = a})
.FirstOrDefault(p => p.Array.SequenceEqual(SubState))
?.Index;
if (nextStateIndex.HasValue) {
...
}
Note: this code uses the new ?. operator. If you are targeting C# version that does not have support for this operator, store FirstOrDefault result for an explicit null checking.
You can use Linq:
var index = -1;
var foundSubState = States.FirstOrDefault(x => {
index++;
return x.SequenceEqual(SubState);
});
var res = foundSubState != default(Array) ? index : -1;

Find all index numbers of a value in array [duplicate]

This question already has answers here:
c# Array.FindAllIndexOf which FindAll IndexOf
(10 answers)
Closed 8 years ago.
How to find all positions of a value in array
class Program
{
static void Main(string[] args)
{
int start = 0;
int[] numbers = new int[7] { 2,1,2,1,5,6,5};
}
Something like that:
int[] numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
int toFind = 5;
// all indexes of "5" {4, 6}
int[] indexes = numbers
.Select((v, i) => new {
value = v,
index = i
})
.Where(pair => pair.value == toFind)
.Select(pair => pair.index)
.ToArray();
List<int> indexes = new List<int>();
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == yourNumber)
indexes.Add(i);
}
Useage is: Array.indexOf(T,value)
please refere to the msdn below.
http://msdn.microsoft.com/en-us/library/system.array.indexof(v=vs.110).aspx
You can make a really simple extension method for sequences to do this:
public static class SequenceExt
{
public static IEnumerable<int> IndicesOfAllElementsEqualTo<T>
(
this IEnumerable<T> sequence,
T target
) where T: IEquatable<T>
{
int index = 0;
foreach (var item in sequence)
{
if (item.Equals(target))
yield return index;
++index;
}
}
}
The extension method works with List<>, arrays, IEnumerable<T> and other collections.
Then your code would look something like this:
var numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
var indices = numbers.IndicesOfAllElementsEqualTo(5); // Use extension method.
// Make indices into an array if you want, like so
// (not really necessary for this sample code):
var indexArray = indices.ToArray();
// This prints "4, 6":
Console.WriteLine(string.Join(", ", indexArray));
Linq could help
var indexes = numbers
.Select((x, idx) => new { x, idx })
.Where(c => c.x == number)
.Select(c => c.idx);

Select indexes of all elements in sequence

Using LINQ, can I write a statement that will return an IEnumerable of the indexes of items.
Very simple instance:
{1,2,4,5,3}
would just return
{0,1,2,3,4}
and
{1,2,4,5,3}.Where(num => num == 4)
would return
{2}
It isn't exact code, but it should get the idea across.
var a = new[] {1, 2, 4, 5, 3};
//** First, generates a simple sequence with {0,1,2,3,4}
//** using the 2 parameter lambda select
var sequence1 = a.Select((_, index) => index);
//** Second, gets an array with all indexes where the value is 4.
// We need both value and index for the next line to work.
var sequence2 = a.Select((value, index) => new {value, index});
// Get all indexes where the value is 4
var indexArray = sequence2.Where(x => x.value == 4)
.Select(x => x.index).ToArray();
var numbers = Enumerable.Range(1,10).ToList();
int index = -1;
var indices = numbers.Select(x => i++).ToList();
If you're willing to change up your syntax a bit and use an extension method, the following will work. I'm not keen on it as it creates a new sequence for every call.
var sequence = new[] { 1, 2, 4, 5, 3 };
sequence.Indexer().Select(num => num.Item1); // returns {0,1,2,3,4}
sequence.Indexer().Where(num => num.Item2 == 4).Select(num => num.Item1); // returns {2}
private static IEnumerable<Tuple<int, T>> Indexer<T>(this IEnumerable<T> sequence)
{
return sequence.Select((x, y) => new Tuple<int, T>(y, x));
}
A better way would be to change up the way you're writing it altogether:
var sequence = new[] { 1, 2, 4, 5, 3 };
sequence.Select((num, index) => new { Num = num, Index = index }).Select(num => num.Index); // returns {0, 1,2,3,4}
sequence.Select((num, index) => new { Num = num, Index = index }).Where(num => num.Num == 4).Select(num => num.Index); // returns {2}
The full set of indices just depends on the number of items, not on the values, so you can do this:
IEnumerable<int> indices = Enumerable.Range(0, 5);
If you're dealing with an IEnumerable<T>, you could do the following to get the index of the item matching 4:
IEnumerable<int> values = new[] { 1, 2, 3, 4, 5 };
int indexOf4 = (
values.Select((v, i) => new {v, i})
.FirstOrDefault(vi => vi.v == 4) ?? new {v = 0, i = -1}).i;
This copes with the case where the value source doesn't contain a match (returning -1).
Of course, if you don't mind converting your IEnumerable<T> to a list then you can just call IndexOf:
int indexOf4a = values.ToList().IndexOf(4);
But, I suspect what the question is really looking for is a way to find all the indices for values that match a particular predicate. For example:
IEnumerable<int> big = values.Select((v, i) => new {v, i})
.Where(vi => vi.v > 3)
.Select (vi => vi.i);
which returns the indices of the values > 3: [3, 4].
If the predicate doesn't match any values then you'll get an empty enumerable as the result.
IEnumerable<int> seq = new[] { 1, 2, 4, 5, 3 };
// The indexes of all elements.
var indexes = Enumerable.Range(0, seq.Count());
// The index of the left-most element with value 4.
// NOTE: Will return seq.Count() if the element doesn't exist.
var index = seq.TakeWhile(x => x != 4).Count();
// The indexes of all the elements with value 4.
// NOTE: Be careful to enumerate only once.
int current_index = 0;
var all_indexes =
from e in (
from x in seq
select new { x, Index = current_index++ }
)
where e.x == 4
select e.Index;
You can do it like this:
public static IEnumerable<int> WhereIndices<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return source.Select(Tuple.Create<T, int>)
.Where(z => predicate(z.Item1)).Select(z => z.Item2);
}
It's an extension method, so put it in a static non-nested class. Use it just like you use Where, that is:
.WhereIndices(num => num == 4)
This should do it. Not sure how efficient it is though..
List<int> list = new List<int>()
{
1,
2,
3,
4,
5
};
var indexes = list.Select(item => list.IndexOf(item));
var index = list.Where(item => item == 4).Select(item => list.IndexOf(item));

LINQ to count Continues repeated items(int) in an int Array?

Here is an scenario of my question: I have an array, say:
{ 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 }
The result should be something like this (array element => its count):
4 => 1
1 => 2
3 => 2
2 => 1
5 => 1
3 => 1
2 => 2
I know this can be achieved by for loop.
But google'd a lot to make this possible using lesser lines of code using LINQ without success.
I believe the most optimal way to do this is to create a "LINQ-like" extension methods using an iterator block. This allows you to perform the calculation doing a single pass over your data. Note that performance isn't important at all if you just want to perform the calculation on a small array of numbers. Of course this is really your for loop in disguise.
static class Extensions {
public static IEnumerable<Tuple<T, Int32>> ToRunLengths<T>(this IEnumerable<T> source) {
using (var enumerator = source.GetEnumerator()) {
// Empty input leads to empty output.
if (!enumerator.MoveNext())
yield break;
// Retrieve first item of the sequence.
var currentValue = enumerator.Current;
var runLength = 1;
// Iterate the remaining items in the sequence.
while (enumerator.MoveNext()) {
var value = enumerator.Current;
if (!Equals(value, currentValue)) {
// A new run is starting. Return the previous run.
yield return Tuple.Create(currentValue, runLength);
currentValue = value;
runLength = 0;
}
runLength += 1;
}
// Return the last run.
yield return Tuple.Create(currentValue, runLength);
}
}
}
Note that the extension method is generic and you can use it on any type. Values are compared for equality using Object.Equals. However, if you want to you could pass an IEqualityComparer<T> to allow for customization of how values are compared.
You can use the method like this:
var numbers = new[] { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var runLengths = numbers.ToRunLengths();
For you input data the result will be these tuples:
4 1
1 2
3 2
2 1
5 1
3 1
2 2
(Adding another answer to avoid the two upvotes for my deleted one counting towards this...)
I've had a little think about this (now I've understood the question) and it's really not clear how you'd do this nicely in LINQ. There are definitely ways that it could be done, potentially using Zip or Aggregate, but they'd be relatively unclear. Using foreach is pretty simple:
// Simplest way of building an empty list of an anonymous type...
var results = new[] { new { Value = 0, Count = 0 } }.Take(0).ToList();
// TODO: Handle empty arrays
int currentValue = array[0];
int currentCount = 1;
foreach (var value in array.Skip(1))
{
if (currentValue != value)
{
results.Add(new { Value = currentValue, Count = currentCount });
currentCount = 0;
currentValue = value;
}
currentCount++;
}
// Handle tail, which we won't have emitted yet
results.Add(new { Value = currentValue, Count = currentCount });
Here's a LINQ expression that works (edit: tightened up code just a little more):
var data = new int[] { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var result = data.Select ((item, index) =>
new
{
Key = item,
Count = (index == 0 || data.ElementAt(index - 1) != item)
? data.Skip(index).TakeWhile (d => d == item).Count ()
: -1
}
)
.Where (d => d.Count != -1);
And here's a proof that shows it working.
This not short enough?
public static IEnumerable<KeyValuePair<T, int>> Repeats<T>(
this IEnumerable<T> source)
{
int count = 0;
T lastItem = source.First();
foreach (var item in source)
{
if (Equals(item, lastItem))
{
count++;
}
else
{
yield return new KeyValuePair<T, int>(lastItem, count);
lastItem = item;
count = 1;
}
}
yield return new KeyValuePair<T, int>(lastItem, count);
}
I'll be interested to see a linq way.
I already wrote the method you need over there. Here's how to call it.
foreach(var g in numbers.GroupContiguous(i => i))
{
Console.WriteLine("{0} => {1}", g.Key, g.Count);
}
Behold (you can run this directly in LINQPad -- rle is where the magic happens):
var xs = new[] { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var rle = Enumerable.Range(0, xs.Length)
.Where(i => i == 0 || xs[i - 1] != xs[i])
.Select(i => new { Key = xs[i], Count = xs.Skip(i).TakeWhile(x => x == xs[i]).Count() });
Console.WriteLine(rle);
Of course, this is O(n^2), but you didn't request linear efficiency in the spec.
var array = new int[] {1,1,2,3,5,6,6 };
foreach (var g in array.GroupBy(i => i))
{
Console.WriteLine("{0} => {1}", g.Key, g.Count());
}
var array = new int[]{};//whatever ur array is
array.select((s)=>{return array.where((s2)=>{s == s2}).count();});
the only prob with is tht if you have 1 - two times you will get the result for 1-two times
var array = new int[] {1,1,2,3,5,6,6 };
var arrayd = array.Distinct();
var arrayl= arrayd.Select(s => { return array.Where(s2 => s2 == s).Count(); }).ToArray();
Output
arrayl=[0]2 [1]1 [2]1 [3]1 [4]2
Try GroupBy through List<int>
List<int> list = new List<int>() { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var res = list.GroupBy(val => val);
foreach (var v in res)
{
MessageBox.Show(v.Key.ToString() + "=>" + v.Count().ToString());
}

Categories

Resources