Finding the last index of an array - c#

How do you retrieve the last element of an array in C#?

LINQ provides Last():
csharp> int[] nums = {1,2,3,4,5};
csharp> nums.Last();
5
This is handy when you don't want to make a variable unnecessarily.
string lastName = "Abraham Lincoln".Split().Last();

With C# 8:
int[] array = { 1, 3, 5 };
var lastItem = array[^1]; // 5

The array has a Length property that will give you the length of the array. Since the array indices are zero-based, the last item will be at Length - 1.
string[] items = GetAllItems();
string lastItem = items[items.Length - 1];
int arrayLength = array.Length;
When declaring an array in C#, the number you give is the length of the array:
string[] items = new string[5]; // five items, index ranging from 0 to 4.

New in C# 8.0 you can use the so-called "hat" (^) operator! This is useful for when you want to do something in one line!
var mystr = "Hello World!";
var lastword = mystr.Split(" ")[^1];
Console.WriteLine(lastword);
// World!
instead of the old way:
var mystr = "Hello World";
var split = mystr.Split(" ");
var lastword = split[split.Length - 1];
Console.WriteLine(lastword);
// World!
It doesn't save much space, but it looks much clearer (maybe I only think this because I came from python?). This is also much better than calling a method like .Last() or .Reverse() Read more at MSDN
Edit: You can add this functionality to your class like so:
public class MyClass
{
public object this[Index indx]
{
get
{
// Do indexing here, this is just an example of the .IsFromEnd property
if (indx.IsFromEnd)
{
Console.WriteLine("Negative Index!")
}
else
{
Console.WriteLine("Positive Index!")
}
}
}
}
The Index.IsFromEnd will tell you if someone is using the 'hat' (^) operator

Use Array.GetUpperBound(0). Array.Length contains the number of items in the array, so reading Length -1 only works on the assumption that the array is zero based.

To compute the index of the last item:
int index = array.Length - 1;
Will get you -1 if the array is empty - you should treat it as a special case.
To access the last index:
array[array.Length - 1] = ...
or
... = array[array.Length - 1]
will cause an exception if the array is actually empty (Length is 0).

Also, starting with .NET Core 3.0 (and .NET Standard 2.1) (C# 8) you can use Index type to keep array's indexes from end:
var lastElementIndexInAnyArraySize = ^1;
var lastElement = array[lastElementIndexInAnyArraySize];
You can use this index to get last array value in any length of array. For example:
var firstArray = new[] {0, 1, 1, 2, 2};
var secondArray = new[] {3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5};
var index = ^1;
var firstArrayLastValue = firstArray[index]; // 2
var secondArrayLastValue = secondArray[index]; // 5
For more information check documentation

The following will return NULL if the array is empty, else the last element.
var item = (arr.Length == 0) ? null : arr[arr.Length - 1]

say your array is called arr
do
arr[arr.Length - 1]

Is this worth mentioning?
var item = new Stack(arr).Pop();

Array starts from index 0 and ends at n-1.
static void Main(string[] args)
{
int[] arr = { 1, 2, 3, 4, 5 };
int length = arr.Length - 1; // starts from 0 to n-1
Console.WriteLine(length); // this will give the last index.
Console.Read();
}

static void Main(string[] args)
{
int size = 6;
int[] arr = new int[6] { 1, 2, 3, 4, 5, 6 };
for (int i = 0; i < size; i++)
{
Console.WriteLine("The last element is {0}", GetLastArrayIndex(arr));
Console.ReadLine();
}
}
//Get Last Index
static int GetLastArrayIndex(int[] arr)
{
try
{
int lastNum;
lastNum = arr.Length - 1;
return lastNum;
}
catch (Exception ex)
{
return 0;
}
}

This is simplest and works on all versions.
int[] array = { 1, 3, 5 };
int last = array[array.Length - 1];
Console.WriteLine(last);
// 5

Related

Getting wrong range of numbers

Given the pair of 2 strings "2-4,6-8" I want to separate these 2 pairs and find all numbers between those range.
So first pair 2-4 should return me 2, 3, 4
Second pair 6-8 should return 6, 7, 8
I tried below code
var splittedString = ln.Split(",");
var firstPair = splittedString[0];
var secondPair = splittedString[1];
var splittedFirstPair = firstPair.Split("-");
IEnumerable<int> firsPairRange = Enumerable.Range(
Convert.ToInt32(splittedFirstPair[0]),
Convert.ToInt32(splittedFirstPair[1]));
var splittedSecondPair = secondPair.Split("-");
IEnumerable<int> secondPairRange = Enumerable.Range(
Convert.ToInt32(splittedSecondPair[0]),
Convert.ToInt32(splittedSecondPair[1]));
But the variable firsPairRange gives me output 2,3,4,5 and the variable secondPairRange gives me output 6,7,8,9,10,11,12,13
I don't understand why and how to fix it?
Instead of Enumerable.Range(start,end), the second parameter needs to be the count of elements including the last element
Enumerable.Range(start,end-start+1)
string ln = "2-4,6-8";
var splittedString = ln.Split(',').Select(x => x.Split('-').Select(int.Parse).ToArray());
int[] first = splittedString.ElementAt(0);
int[] second = splittedString.ElementAt(1);
var firstPairRange = Enumerable.Range(first[0], first[1] - first[0] + 1);
var secondPairRange = Enumerable.Range(second[0], second[1] - second[0] + 1);
Enumerable.Range has two parameters:
the start
the count(!)
So this gives you already enough information to fix it. Your start is 2 and the count is 4 because of 2-4 but you want 4-2+1=3 as count:
IEnumerable<int> firstPairRange = Enumerable.Empty<int>();
if (splittedFirstPair.Length == 2
&& int.TryParse(splittedFirstPair[0], out int first)
&& int.TryParse(splittedFirstPair[1], out int second)
&& second >= first)
{
int count = second - first + 1;
firstPairRange = Enumerable.Range(first, count);
}
In general case (negative numbers, single numbers) when we allow strings like this
-9,2-4,6-8,-5,7,-3-5,-8--2
we can put it as
private static IEnumerable<IEnumerable<int>> Ranges(string text) {
foreach (var range in text.Split(',')) {
var match = Regex.Match(range,
#"^\s*(?<left>-?[0-9]+)\s*-\s*(?<right>-?[0-9]+)\s*$");
if (match.Success) {
int left = int.Parse(match.Groups["left"].Value);
int right = int.Parse(match.Groups["right"].Value);
yield return Enumerable.Range(left, right - left + 1);
}
else
yield return new[] { int.Parse(range) };
}
}
Demo:
string text = "-9,2-4,6-8,-5,7,-3-5,-8--2";
var result = string.Join(Environment.NewLine, Ranges(text)
.Select(range => string.Join(", ", range)));
Console.Write(result);
Output:
-9
2, 3, 4
6, 7, 8
-5
7
-3, -2, -1, 0, 1, 2, 3, 4, 5
-8, -7, -6, -5, -4, -3, -2
You are providing wrong values to Enumerable.Range() function. Its syntax is Enumerable.Range(int start, int count). In start, you have to give first integer in the sequence and in count, you have to give number of integers to be generated in sequence. If you correct your count, right sequence will be generated. Replace your lines with the following lines:
IEnumerable<int> firsPairRange = Enumerable.Range(Convert.ToInt32(splittedFirstPair[0]), Convert.ToInt32(splittedFirstPair[1]) - Convert.ToInt32(splittedFirstPair[0]) + 1);
IEnumerable<int> secondPairRange = Enumerable.Range(Convert.ToInt32(splittedSecondPair[0]), Convert.ToInt32(splittedSecondPair[1]) - Convert.ToInt32(splittedSecondPair[0]) + 1);

How to get permutations with odd transpositions?

I have an algorithm with all possible permutations, can i get permutations with only odd transpositions. Or simplify the algorithm to find only such permutations. For example, array {1,2,3,4}. If I move one element I will get only one transposition, and it odd tansposition: {2,1,3,4}, {3,2,1,4}, {4,2,3,1}, {1,3,2,4}, {1,4,3,2}, {1,2,4,3}.
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 2, 3, 4 };
ShowAllCombinations(arr);
Console.Read();
}
public static void ShowAllCombinations<T>(IList<T> arr, string current = "")
{
if (arr.Count == 0)
{
Console.WriteLine(current);
return;
}
for (int i = 0; i < arr.Count; i++)
{
List<T> lst = new List<T>(arr);
lst.RemoveAt(i);
ShowAllCombinations(lst, current + arr[i].ToString());
}
}
}
This algorithm gives all permutations, but not only odd ones.
Your ShowAllCombinations method is inconvenient, the string should stay a list so you can process the elements.
Once you have a complete list of elements, you can "unpermute" back to the natural order and count the number of swaps. This assumes unique elements (no repetitions) and that the list is one-based. Note that this method permutes the list, will want to create a copy somewhere.
public void SwapCount(List<int> arr)
{
var swapCount = 0;
// double for loop, compare the value at the outer position
// to the value at the inner position.
for (var i=0; i<arr.Count; i++)
{
// Start at the index after the outer loop
for (var j=i+1; j<arr.Count; j++)
{
// If the inner value is what the outer value
// is supposed to be then swap it.
if (arr[j] == i+1)
{
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
swapCount++;
}
}
}
Console.WriteLine($"swap count: {swapCount}");
}
output
> SwapCount(new List<int>() { 1, 2, 3, 4 })
swap count: 0
> SwapCount(new List<int>() { 2, 1, 3, 4 })
swap count: 1
> SwapCount(new List<int>() { 1, 3, 2, 4 })
swap count: 1
> SwapCount(new List<int>() { 1, 3, 4, 2})
swap count: 2
>
This is ~ O(n^2), but I'm assuming performance is not so important here. You can find more efficient algorithms here: Parity of permutation with parallelism

C# Sort an array by absolute value does not work as intended with a input array

Sorting arrays by absolute value using a input array refuses to work but replacing it with a simple array works. I have no idea why it doesn't work, I just don't see what is wrong.
I need the result to be like this:
Input: -5 4 8 -2 1
Output: 1 -2 4 -5 8
static void Main()
{
var sampleInput = Console.ReadLine().Split().Select(int.Parse).ToArray();
int[] x = sampleInput;
int n = sampleInput.Length;
int[] output = new int[n];
string sOutput = string.Empty;
int start = 0;
int last = n - 1;
while (last >= start)
{
n--;
if (Math.Abs(x[start]) > Math.Abs(x[last]))
{
output[n] = x[start++];
}
else
{
output[n] = x[last--];
}
sOutput = output[n].ToString() + " " + sOutput;
}
Console.Write(sOutput);
}
why not
using System.Linq;
var sorted = new [] {-5, 4, 8, -2 , 1}.OrderBy(Math.Abs);
(and of course to get an Array, you can tack on a .ToArray() at the end there).
And to pass what you want:
var sampleInput = Console.ReadLine().Split().Select(int.Parse).ToArray();
var sorted = sampleInput.OrderBy(Math.Abs);
Here is your solution.
var array = Console.ReadLine().Split(' ').Select(s => int.Parse(s)).ToArray();
var sorted = array.OrderBy(Math.Abs);
foreach (int element in sorted)
{
Console.WriteLine(element);
}
Kind regards,
A classmate?

Why this reverse array method isnt working?

I am trying to make a method to reverse an array, I don't know why it is not working?
When I said int[] arr = array, I want to do this so it will not be affected so I can use the elements for the second for loop and it should have elements {1,2,3,4,5,6} but when I use
for (int i=array.Length-1;i>array.Length/2;i--)
{
array[i] = arr[array.Length - 1 - i];
}
In this case I have 6 elements so array.Length is 6 and since I started from array.Length-1 it must start from the last element and it must be array[5]=arr[6-1-5] which must be array[5]=arr[0] and arr[0] is 1 but I think it is getting it as 6, why?
Here is the complete code:
// ReverseArray method
static int [] ReverseArray(int [] array)
{
int[] arr = array;
for (int i=0; i<array.Length/2;i++)
{
array[i] = array[array.Length-1 - i];
}
for (int i=array.Length-1;i>array.Length/2;i--)
{
array[i] = arr[array.Length - 1 - i];
}
return array;
}
// Method for displaying elements of Array
static void DisplayArray(int [] array)
{
int i;
Console.Write("{");
for (i = 0; i < array.Length-1; i++)
{
Console.Write(array[i] + ",");
}
Console.WriteLine(array[i] + "}");
}
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 ,6};
ReverseArray(array);
DisplayArray(array);
Console.ReadKey();
}
Your reversal approach is invalid: rather than swapping elements at indexes i and array.Length-1 - i, your code copies the tail portion of the array onto the initial one, effectively "folding" the array onto itself.
You need to remove the second loop, and replace the assignment with a swap: make a temporary variable, store array[i], copy array[array.Length-1 - i], then write the temporary in its place.
I couldn't help myself but start to write a piece of code trying to solve it.
int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
arr = Reverse(arr).ToArray();
Here is the shorter way to achieve that.
public IEnumerable<int> Reverse(int[] arr)
{
for (int i = arr.Length-1; i >= 0; i--)
{
yield return arr[i];
}
}

How do I delete all elements in an int array that exist in another int array?

In my C# program, I have an int array containing a set of integers and occasionally duplicates of those integers. I want to create an array that only contains the numbers that exist as duplicates in the initial array, but in itself contains no duplicates. Based on my newbie understanding of C# I thought that the following code would do the trick:
int a = 9;
int b = 6;
int c = 3;
int index = 0;
int[] mltpls = new int[a + b + c];
while (a > 0)
{
mltpls[index] = 2 * a;
a -= 1;
index += 1;
}
while(b > 0)
{
mltpls[index] = 3 * b;
b -= 1;
index += 1;
}
while(c > 0)
{
mltpls[index] = 5 * c;
c -= 1;
index += 1;
}
int[] mltpls_unique = mltpls.Distinct().ToArray();
int[] mltpls_dplcts = mltpls.Except(mltpls_unique).ToArray();
Console.WriteLine(mltpls_dplcts);
//EDIT
//By running the following code I can write out all numbers in "mltpls"
for (int i = 0; i < mltpls.Length; i++)
{
Console.Write(mltpls[i] + ", ");
}
/*If I try to run equivalent code for the "mltpls_dplcts" array nothing
only a blank line is displayed.*/
When I run this goal my the final result of my console application is a blank row. My interpretation of this is that the array mltpls_dplcts is empty or that I'm incorrectly going about printing the array.
How do get only the duplicate values from an array?
My interpretation of this is that the array mltpls_dplcts is empty or that I'm incorrectly going about printing the array.
Both interpretations are correct
Distinct will return every item that is at least once present in mltps. If you now apply Except you get nothing because all items that are in mltpls_unique are also present in mltps. The items in the array are compared by value, so for Except it does not matter whether a number occurs multiple times in the other array. If it is there once it will not return the number. So you get an empty array.
Furthermore you cannot simply shove an entire array into Console.WriteLine. Either use a loop or String.Join to print the content:
Console.WriteLine(String.Join(" ",mltpls_dplcts));
Solution: You can solve it using a good old loop approach ;)
int[] mltpls_unique = mltpls.Distinct().ToArray();
// The amount of duplicates is the difference between the original and the unique array
int[] mltpls_dplcts = new int[mltpls.Length-mltpls_unique.Length];
int dupCount = 0;
for (int i = 0; i < mltpls.Length; i++)
{
for (int j = i+1; j < mltpls.Length; j++)
{
if (mltpls[i] == mltpls[j])
{
mltpls_dplcts[dupCount] = mltpls[i];
dupCount++;
}
}
}
Output: 18 12 10 6 15
You cannot print the array directly. You need to loop and print one by one:
foreach (var element in mltpls_dplcts)
{
Console.WriteLine(element);
}
You can get array of distinct duplicates like this:
var duplicates = mltpls.GroupBy(o => o)
.Where(g => g.Count() > 1)
.Select(g => g.First()).ToArray();
To get new array that contains only the elements from the original one that are not in the second array you can use:
var newArr = mltpls.Except(duplicates).ToArray();
It is not proper way to find duplicates. You can determine the duplicates by using GroupBy and print them to console like this;
var mltpls_dplcts = mltpls.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key).ToArray();
foreach (var duplicate in mltpls_dplcts)
{
Console.WriteLine(duplicate);
}
Also, If it isn't must to use Array for you, I suggest you to use List<int>.
Updated question from OP:
How do get only the duplicate values from an array?
var arr1 = new[] {1, 2, 4, 4, 5, 5, 5, 5, 6, 7, 1};
var duplicates = arr1.ToLookup(_ => _, _ => _).Where(_ => _.Count()>1).Select(_ => _.Key).ToArray();
// duplicates is now { 1, 4, 5 }
Original question from OP:
How do I delete all elements in an int array that exist in another int array in C#?
var arr1 = new[] {1, 2, 4, 5, 6, 7};
var arr2 = new[] {4, 5};
var hash = new HashSet<int>(arr1);
hash.ExceptWith(arr2);
var filteredArray = hash.ToArray();
// filteredArray is now { 1, 2, 6, 7 }

Categories