Group the indexes of the same elements in a array in C# - c#

There is a int[] array that stores different numbers.
What I want is to group the indexes of those same numbers in the array to the same groups.
For exmaple, the array is int[5]{1,2,5,1,5}
I would like to see the output is List<List<int>> { {0,3}, {1}, {2,4} } // don't mind syntax
It's better if Linq (or a more efficient way) can be used, thanks for help.

You can simply use GroupBy and the position obtained from the Select overload:
int[] array;
var result = array.Select((v, idx) => new { Value = v, Index = idx })
.GroupBy(g => g.Value)
.Select(g => g.ToArray()) // inner array
.ToArray(); // outer array

One of ways:
var result = myArray.Select((elem, idx) => new { Value = elem, Idx = idx})
.GroupBy(proxy => proxy.Value);
foreach (var grouped in result)
{
Console.WriteLine("Element {0} has indexes: {1}",
grouped.Key,
string.Join(", ", grouped.Select(proxy => proxy.Idx).ToArray()));
}
var myFinalList = result.Select(proxy => proxy.ToArray()).ToList();

You can use Enumerable.Range combined with GroupBy:
int[] arr = { 1, 2, 5, 1, 5 };
var result = Enumerable.Range(0, arr.Length)
.GroupBy(i => arr[i])
.Select(x => x.ToList()).ToList();
DEMO HERE

Related

why do I have System.Int32[] as output when I try to return my array?

I'm trying to find the unique numbers inside of an array. and return it as an array of integers: for example if I have this array: arr = [2,3,2,6,2], my output should be: [3,6]
public static int[] unique(int[] arr)
{
var uniqueList = arr.GroupBy(n => n).Where(item => item.Count() == 1).Select(item => item.Key);
int[] r = uniqueList.OrderBy(item => item).ToArray();
foreach (int item2 in r)
{
r = uniqueList.OrderBy(item => item2).ToArray();
Console.WriteLine(r);
Console.WriteLine(item2);
}
return r;
}
}
You can do it in one shot by adding OrderBy and ToArray to your Linq. I would also give a better name to my method and organize my linq for readability sake.
static int[] GetUniqueNumbers(int[] arr)
{
var uniqueList = arr
.GroupBy(n => n)
.Where(item => item.Count() == 1)
.Select(item => item.Key)
.OrderBy(e => e)
.ToArray();
return uniqueList;
}
To testing it:
var arr = new int[] { 2, 6, 2, 3, 2 };
var numbers = GetUniqueNumbers(arr);
foreach (var i in numbers)
{
Console.WriteLine(i);
}
And the output is
3
6

Converting IEnumerable<IEnumerable<T>> to List<string>

I’m trying to convert from this answer the code:
static IEnumerable<IEnumerable<T>> GetKCombs<T>(IEnumerable<T> list, int length) where T : IComparable
{
if (length == 1) return list.Select(t => new T[] { t });
return GetKCombs(list, length - 1)
.SelectMany(t => list.Where(o => o.CompareTo(t.Last()) > 0),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
Into a list of strings. For example I want this output {1,2} {1,3} to convert it to "1,2","1,3" (this is 2 seperate string) but I cant get it. I cant even understand how I can read the results of the above function. this is my code:
int[] numbers = ListEditText.Text.Split(',').Select(x => int.Parse(x)).ToArray();
var combinations = GetKCombs(numbers, 2);
stringCombinations = combinations.Select(j => j.ToString()).Aggregate((x, y) => x + "," + y);
In the end all the results i will add them on a List with all the possible unique combinations
For example for the numbers {1,2,3} i want this List:
'1','2','3','1,2','1,3','2,3','1,2,3'
This is my code right now:
List<string> stringCombinations = new List<string>();
for (int i = 0; i < numbers.Count(); i++)
{
combinations = GetKCombs(numbers, i + 1).Select(c => string.Join(",", c));
stringCombinations.AddRange(combinations);
}
You can try first joining the results of the inner IEnumerables
var combinations = GetKCombs(numbers, 2).Select(c => string.Join(",", c));
and then concatenating them into a single string
var combinationString = string.Join("; ", combinations); // "1,2; 1,3"
Based on your edits -- if I got you right -- you can try doing
var combinationStrings =
numbers
.SelectMany((_, i) =>
GetKCombs(numbers, i + 1) // get combinations for each 'length'
.Select(c => string.Join(",", c))) // join them to a string
.ToList();
Try
var stringCombinations = string.Join(",", combinations.Select(j => $#"""{string.Join(",", j)}"""));
It prints exactly the output you want.

Splitting byte list into position lists C#

So I have a list of bytes
List<byte> s = {1,2,3,2,2,2,3,1,2,4,2,1,4,.....};
I want to get new position lists using index of element.To something like this...
List<byte> 1 = {0,7,11};
List<byte> 2 = {1,3,4,5,8,10};
List<byte> 3 = {2,6};
List<byte> 4 = {9,12};
List<byte> 5 = ..... and so on
What`s the best way of doing this?
thank you.
You can use GroupBy and ToDictionary to get Dictionary<byte, List<int>>:
var dict = s.Select((value, index) => new { value, index })
.GroupBy(x => x.value)
.ToDictionary(g => g.Key, g => g.Select(x => x.index).ToList());
With LINQ, you can create an ILookup<TKey, TElement> with the desired results like this:
var indicesByByte = s.Select((item, index) => new { Item = item, Index = index } )
.ToLookup(tuple => tuple.Item, tuple => tuple.Index);
Now,
indicesByByte[0] will be a sequence containing {0,7,11}
indicesByByte[1] will be a sequence containing {1,3,4,5,8,10}
etc.
One way to do this is with LINQ, using the overload of Enumerable<T>.Select which contains the index, then grouping:
var groups = s.Select((item, index) => new {index, item})
.GroupBy(x => x.item, x => x.index)
.ToDictionary(x => x.Key, x => x.ToList());
This will return a Dictionary<byte, List<int>> where the key is the value (1, 2, 3, 4, 5 in your example) and the value contains a list of positions.
You could also do it using a for loop, in a single pass:
var groups = new Dictionary<byte, List<int>>();
for (int i = 0; i < s.Count; i++)
{
if(!groups.ContainsKey(s[i]))
groups[s[i]] = new List<int>();
groups[s[i]].Add(i);
}

Concatinating values of a matching string in an arrray

I have a string array[2] as follows:
1st Array 2nd Aray
"100101" "Testing123"
"100102" "Apple123"
"100101" "Dog123"
"100104" "Cat123"
"100101" "Animal123"
I would like to concatenate all elements of the 2nd array if the elements in the first array match.
For example elements of the first array that match are "100101", "100101" and "100101". So a string with the concatenated values of the respective 2nd array would be as follows:
"Testing123 Dog123 Animal123"
How could this be achieved elegantly?
I did it this way:
var results =
array1
.Zip(array2, (x1, x2) => new { x1, x2 })
.ToLookup(x => x.x1, x => x.x2)
.Select(x => new { x.Key, Value = String.Join(" ", x), });
I got this result:
If you needed to extract the results in a different way it wouldn't be too hard to fiddle with my method to get what you need.
You can use GroupBy:
var strings = array1.Select((s,index) => new{ s, index })
.GroupBy(x => x.s)
.Select(g =>
string.Join(" ", g.Select(x => array2.ElementAtOrDefault(x.index))));
foreach(string s in strings)
Console.WriteLine(s);
If you want to concatenate only strings which are duplicates in the first array, add this Where:
// ...
.GroupBy(x => x.s)
.Where(g => g.Count() > 1)
// ...
Here's a Demo
var indices = array1.Select((i, s) => new {Index = i, Str = s})
.Where(e => e.Str == "100101")
.Select(e => e.Index);
string result = string.Join(" ", array2.Select((i, s) => new {Index = i, Str = s})
.Where(e => indices.Contains(e.Index))
.Select(e => e.Str));
assuming both arrays are the same length, this should give you the output you need.
var array1 = new[] {"100101", "100102", "100101", "100104","100101" };
var array2 = new[] { "Testing123", "Apple123", "Dog123","Cat123", "Animal123" };
var result = new Dictionary<string, string>();
for (int i = 0; i < array1.Length; i++)
{
// if the value has been found before
if( result.ContainsKey( array1[i] ) ) {
result[array1[i]] += " " + array2[i]; // append to existing "matched" entry
}
else {
result.Add(array1[i], array2[i]); // add new unique value
}
}
You can zip these two arrays as they are of same size. Then group the elements by first array value.
Then join the elements.
I wrote a sample program using linq
string[] array1 = new string[]{"100101","100102","100101","100104","100101"};
string[] array2 = new string[] { "Testing123", "Apple123", "Dog123", "Cat123", "Animal123" };
var concatenatedString = array1.Zip(array2, (x, y) => new { First = x, Second = y }).GroupBy(t => t.First).Select(t=> string.Join(" ",t.Select(s=> s.Second))).ToList();
The result will contain a list of concatenated strings.
Hope it Helps
var arr1 = new [] { "100101", "100102", "100101", "100104", "100101" };
var arr2 = new [] { "Testing123", "Apple123", "Dog123", "Cat123", "Animal123" };
var result = string.Join(" ", arr2.Where((a, i) => i < arr1.Length && arr1[i] == "100101"));

Sort an array and return index of arrays according to elements size in c#

I need to sort the array from minimum to maximum value, but I need to return only the index of array after sorting it. I dont want to swap values, I just need to return the values index according to the value size,
for eg
int[] arr = {7,8,2,3,1,5};
for (int i=0; i<=arr.length; i++)
{
int index = Array.IndexOf(arr, i);
}
Now I want to return index of values from minimum to maximum
as 4,2,3,5,0,1.
Your check in the for loop is wrong it should be i < arr.Length. For index you can do:
int[] arr = { 7, 8, 2, 3, 1, 5 };
int[] sortedIndexArray = arr.Select((r, i) => new { Value = r, Index = i })
.OrderBy(t => t.Value)
.Select(p => p.Index)
.ToArray();
For output:
foreach(int item in sortedIndexArray)
Console.WriteLine(item);
Output:
4
2
3
5
0
1
var indexes = arr.Select((i, inx) => new { i, inx })
.OrderBy(x => x.i)
.Select(x => x.inx)
.ToArray();

Categories

Resources