How to initialize a string or char jagged array in C#? - c#

Besides using a loop. An int array can be initialized with 0s easy like arr = Enumerable.Range(0, 100).Select(i => new int[100]).ToArray();.
Is there a way I can initialize a string or char array in a similar fashion?

I think you're looking for:
string[] arrayOfStringZeros = Enumerable.Range(0, 100)
.Select(i => "0")
.ToArray();
char[] arrayOfCharZeros = Enumerable.Range(0, 100)
.Select(i => '0')
.ToArray();
Updated
char[][] jaggedOfCharZeros = Enumerable.Range(0, 100)
.Select(i => Enumerable.Range(0, 100)
.Select(j => '0')
.ToArray())
.ToArray();
Actually it would probably be slightly more efficient to do:
char[] initZeros = Enumerable.Range(0, 100)
.Select(i => '0')
.ToArray();
char[][] jaggedOfCharZeros = Enumerable.Range(0, 100)
.Select(i => (char[])initZeros.Clone())
.ToArray();

Related

C#:How to get the longest common prefix from a list of strings LINQ expression

I am trying to learn LINQ
I would like to understand how to get the longest common prefix from a list of strings
{"a","abC","abcD"}
would return "ab". Common as in at least 1 other string has it. Even though "a" is common for all 3, I would like to get "ab" because 2 elements share this prefix and "ab" is longer than "a"
It was an interesting challenge and this is my solution:
var array = new []{"a","abC","abcD"};
var longestCommonPrefix = Enumerable.Range(1, array.Max(_ => _)!.Length)
.Select(i =>
{
var grouped = array.Where(x => x.Length >= i)
.GroupBy(x => x[..i])
.Where(x => x.Count() > 1)
.OrderByDescending(x => x.Count())
.Select(x => new { LongestCommonPrefix = x.Key })
.FirstOrDefault();
return grouped?.LongestCommonPrefix ?? string.Empty;
}).Max();
var longestCommonPrefix = (words.FirstOrDefault() ?? String.Empty)
.Substring(0,
Enumerable.Range(0, words.Any() ? words.Min(x => x.Length) + 1 : 0)
.Where(x => words.Select(w => w.Substring(0, x))
.Distinct().Count() == 1).DefaultIfEmpty(0).Max()
);

Calculate Mode Using LINQ C#

I'm new with using Linq and was wondering how I could print out multiple values of my Mode value. At the minute I can only get 1 value from the Mode but I want it to show multiples ones.
string[] list = TextBox1.Text.Split(new string[] { "," },
StringSplitOptions.RemoveEmptyEntries);
int[] numbers = new int[list.Length];
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = Convert.ToInt32(list[i].Trim());
}
int mode = numbers.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
You need to save off the collection before taking the item(s) you want.
string[] list = TextBox1.Text.Split(new string[] { "," },
StringSplitOptions.RemoveEmptyEntries);
IEnumerable<IGrouping<int, int>> modes = list.GroupBy(v => v);
IEnumerable<IGrouping<int, IGrouping<int, int>>> groupedModes = modes.GroupBy(v => v.Count());
var sortedGroupedModes = groupedModes.OrderByDescending(g => g.Key).ToList();
TextBox2.Text = string.Join(" ", sortedGroupedModes[0].Select(x => x.Key)));
You could get all of the groups and just extract those with the highest count (including ties):
var counts = numbers.GroupBy(v => v)
.Select(g => g.Key, Count = g.Count())
.OrderByDescending(g => g.Count);
var modes = numbers.Where(g => g.Count == counts.First().Count)
.Select(g => g.Key);

C# double for comprehension?

Is it possible to do a double for comprehension in C#? For example, the following works:
var a = new[] { 1, 2, 3 };
var b = Enumerable.Range(0, a.Length).Select(i => a[i]).ToArray();
But when I try and adapt this code for the two-dimensional case, things don't work. Below I'm trying to iterate over the pixels of a bitmap:
Color[] p = Enumerable.Range(0, Source.Width).Select(i => Enumerable.Range(0, Source.Height).Select(j => Source.GetPixel(i, j))).ToArray().
Is there any way to get what I want? The error I'm currently getting is:
Cannot implicitly convert type
System.Collections.Generic.IEnumerable[] to
System.Drawing.Color[]
The outer Select needs to be a SelectMany to flatten the projection:
Color[] p = Enumerable.Range(0, Source.Width)
.SelectMany(i => Enumerable.Range(0, Source.Height)
.Select(j => Source.GetPixel(i, j)))
.ToArray();
or to create a jagged 2-D array add an inner ToArray():
Color[][] p = Enumerable.Range(0, Source.Width)
.Select(i => Enumerable.Range(0, Source.Height)
.Select(j => Source.GetPixel(i, j))
.ToArray())
.ToArray();

Find multiple index in array

Say I have an array like this
string [] fruits = {"watermelon","apple","apple","kiwi","pear","banana"};
Is there an built in function that allows me to query all the index of "apple" ?
For example,
fruits.FindAllIndex("apple");
will return an array of 1 and 2
If there is not, how should I implement it?
Thanks!
LINQ version:
var indexes = fruits.Select((value, index) => new { value, index })
.Where(x => x.value == "apple")
.Select(x => x.index)
.ToList();
Non-LINQ version, using Array<T>.IndexOf() static method:
var indexes = new List<int>();
var lastIndex = 0;
while ((lastIndex = Array.IndexOf(fruits, "apple", lastIndex)) != -1)
{
indexes.Add(lastIndex);
lastIndex++;
}
One way would be to write like this:
var indices = fruits
.Select ((f, i) => new {f, i})
.Where (x => x.f == "apple")
.Select (x => x.i);
Or the traditional way:
var indices = new List<int>();
for (int i = 0; i < fruits.Length; i++)
if(fruits[i] == "apple")
indices.Add(i);
Pretty easy with an extension method.
var fruits = new[] { "watermelon","apple","apple","kiwi","pear","banana" };
var indexes = fruits.FindAllIndexes("apple");
public static class Extensions
{
public static int[] FindAllIndexes(this string[] array, string search) => array
.Select((x, i) => (x, i))
.Where(value => value.x == search)
.Select(value => value.i)
.ToArray();
}

How to limit searching characters if I use LINQ

I have a function that returns duplicated (occur 2 or more times) characters in text. I do it with LINQ:
public char[] linq(string text)
{
char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key).ToArray();
return result;
}
But this way returns duplicated occurrences of all characters in the text (string). How to limit searching, if I want to search just English alphabet characters: abcdefghi....etc.
Thanx for help.
Something like this?
linq("and a rhino 11", new char[] { 'a', 'b', 'c' }); // result: { 'a' }
public char[] linq(string text, char[] limitChars)
{
char[] result = text
.Where( c => limitChars.Contains(c))
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToArray();
return result;
}
This solution only applies if you need to limit the character range to a configurable list.
Note that the char.IsLetter() method will allow characters from other alphabets (i.e. cyrillic, greek, etc.) to pass as well, so this might not be ideal.
Next best thing w/o passing a configurable list is #Femaref's solution imo explicitly using the character codes of the English alphabet - this might work best in your particular problem.
Looks like char.IsLetter() is what you want: char.IsLetter()
This is what you need.
// http://msdn.microsoft.com/en-us/library/system.char.isletter.aspx
private static void Main(string[] args)
{
Console.WriteLine(linq(#"szuizu_4156424324_hjvlahsjlvhlkd_&&ยง"));
Console.Read();
}
public static char[] linq(string text)
{
char[] result = text
.Where(Char.IsLetter)
.GroupBy(x => x)
.Where(g =>g.Count() > 1)
.Select(g => g.Key).ToArray();
return result;
}
char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1 && (g.Key >= 65 && g.Key <= 122))
.Select(g => g.Key).ToArray();
Update from comments:
char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1 && ((g.Key >= 65 && g.Key <= 90) || (g.Key >= 97 && g.Key <= 122)))
.Select(g => g.Key).ToArray();

Categories

Resources