Detecting similar elements in jagged arrays - c#

Is there a way to detect similar elements within multidimensional arrays? For example:
int[][] arrayA = {{1 , 2}, {4 , 6}, {3, 7}};
int[][] arrayB = {{3 , 2}, {1 , 2}, {8, 5}};
Both arrayA and arrayB have the element {1 , 2}. (Or simply, any element in common) Is there a way to detect that it's true?

Yes, you just need to code the logic and you can detect.
bool result = false;
foreach (var arrayAItem in arrayA)
{
foreach (var arrayBItem in arrayB)
{
if (arrayAItem.SequenceEqual(arrayBItem))
{
result = true;
break;
}
}
if (result == true)
{
break;
}
}
and a one liner
bool result = arrayA.Any(arrayAItem => arrayB.Any(arrayBItem => arrayAItem.SequenceEqual(arrayBItem)));

It's hard to give you the answer without just feeding you code, but:
For each element in Array A, check if it's equal to each element in Array B. So basically, you'd need a nested foreach. If you want to record which elements they have in common, add them to a List<ElementType> (not an array since you want to dynamically populate it).
It's not quite that simple since your arrays are nested. You can't just check arrayA[x] == arrayB[x] because you'd be comparing arrays, which are reference types (it would return false unless they both pointed to the same piece of memory). Instead, you'll have to add one more loop inside of the two foreaches you already have to check each int in arrayA against the correlating one in arrayB. int is a value type, so an == comparison would behave how you'd expect it to.

Here is how you can do this (and not only):
var commonItems = from innerA in arrayA
from innerB in arrayB
where innerA.SequenceEqual(innerB)
select innerA;
bool anyCommon = commonItems.Any();
var firstCommon = commonItems.FirstOrDefault();
var commonCount = commonItems.Count();
I guess the variable names are self explanatory :-)

Something along this?
arrayA.Where(arr => arrayB.Any(arr2 => arr1.OrderBy(x => x)
.SequenceEquals(arr.OrderBy(x => x)))).ToArray()
You can remove the two OrderBy calls if you want, depending on how you wish to consider two arrays "the same".

The following code becomes lengthened, but will give you the output you want:
private void TestArrays()
{
int[,] arrayA = new[,] { { 1, 2 }, { 4, 6 }, { 3, 7 } };
int[,] arrayB = new[,] { { 3, 2 }, { 1, 2 }, { 8, 5 } };
int parentLengthA = arrayA.GetLength(0);
int childLengthA = arrayA.GetLength(1);
int parentLengthB = arrayB.GetLength(0);
int childLengthB = arrayB.GetLength(1);
int[] itemsOfA;
int[] itemsOfB;
List<int[]> matchedArrays = new List<int[]>();
for (int i = 0; i < parentLengthA; i++)
{
itemsOfA = new int[childLengthA];
for (int j = 0; j < parentLengthB; j++)
{
itemsOfB = new int[childLengthB];
bool isMatched = true;
if (itemsOfA.Length != itemsOfB.Length)
{
isMatched = false;
break;
}
for (int k = 0; k < itemsOfA.Length; k++)
{
if (arrayA[i, k] != arrayB[j, k])
{
isMatched = false;
break;
}
else
{
itemsOfA[k] = arrayA[i, k];
}
}
if (isMatched)
{
matchedArrays.Add(itemsOfA);
}
}
}
//Just to output the matched array(s)
if (matchedArrays.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach (int[] matchedArray in matchedArrays)
{
foreach (int i in matchedArray)
{
sb.Append(i + ",");
}
sb.AppendLine();
}
MessageBox.Show(sb.ToString());
}
}

Related

C# Algorithm for Combinations/Permutations of a defined range of integers

I am trying to generate a list of unique combinations/permutations of 3 allowable values for 20 different participants (each of the 20 participants can be assigned a value of either 1, 2, or 3).
An example of one combination would be an array on length 20 with all ones like such:
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
...and everything possible all the way up to
{ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }
where each value in the array can be 1, 2 or 3.
I am stuck on writing my GetAllCombinations() function and I looked at some articles on permutation, but everything I have found is just confusing me more. I am not even sure if permutation is what I need here
So far I have this:
public List<int[]> GetValidCombinations()
{
const int positions = 20;
int[] acceptableValues = new int[3] { 1, 2, 3 };
//DO I USE PERMUTATION HERE TO BUILD MY ARRAY LIST OF ALL POSSIBLE COMBINATIONS?
var allPossibleCombinations = GetAllCombinations(positions, acceptableValues);
List<int[]> validList = new List<int[]>();
foreach (var combination in allPossibleCombinations)
{
//omited for berevity but I would
//do some other validations here...
if (true)
{
validList.Add(combination);
}
}
return validList;
}
public List<int[]> GetAllCombinations(int positions, int[] acceptableValues)
{
//For now returning null because I
//don't know How the heck to do this...
return null;
}
I have looked at some examples of permutation and I tried to use something like this below, but it did not produce what I was looking for:
static IEnumerable<IEnumerable<T>>
GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(o => !t.Contains(o)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
public void Test()
{
const int k = 20;
var n = new[] { 1, 2, 3 };
var combinations = GetPermutations(n, k);
//DOES NOT WORK FOR WHAT I NEED
}
Running Test() worked with k was 3 or less but returned nothing if k was greater then 3.
Try this:
public static List<int[]> GetAllCombinations(int position, int[] acceptableVaues)
{
List<int[]> result = new List<int[]>();
int[] parent = new int[] { };
result = AddAPosition(parent, acceptableVaues);
while(position > 1)
{
var tmpResult = new List<int[]>();
foreach(var _parent in result)
{
tmpResult.AddRange(AddAPosition(_parent, acceptableVaues));
}
position--;
result = tmpResult;
}
return result;
}
public static List<int[]> AddAPosition(int[] parent, int[] acceptableValues)
{
List<int[]> result = new List<int[]>();
for (int i = 0; i< acceptableValues.Length; i++)
{
var anArray = new int[parent.Length + 1];
for (int j = 0; j< parent.Length; j++)
{
anArray[j] = parent[j];
}
anArray[parent.Length] = acceptableValues[i];
result.Add(anArray);
}
return result;
}

Comparison of dynamic number of lists in C#

I have a variable number of List-objects, of which I need to compare the values at the same indexes. The number of entries in the list is given and does not vary.
For example:
4 Lists
each 4 entries
So what I'd be looking for in this example, is 4 bools, one per index.
Getting the indexes of unmatching entries would be fine, too.
Pseudo:
bool isFirstEqual = (list1[i] == list2[i] == list3[i] == list4[i]);
But I need to do this in a fashion that's applicable for a variable number of lists. I could have 6 Lists, but also 2.
I was thinking of doing something with LINQs .Except() but am not sure how to use it with a variable number of lists.
I am struggling to find the elegant solution that I'm sure is out there.
Any help on this is appreciated.
If i understand what you mean, something like this might work
public static bool IsEqual<T>(int index, params List<T>[] ary)
{
for (var i = 1; i < ary.Length; i++)
if (!EqualityComparer<T>.Default.Equals(ary[0][index], ary[i][index]))
return false;
return true;
}
Usage
var isSecondelemEqual = IsEqual(1, list1, list2, list3,...)
Update
Basically takes a variable list of lists, and assumes you want to check the index of each list against each other.
bool AreIndexesEqual(int index, List<List<int>> lists)
{
int match = lists[0][index];
foreach(List<int> list in lists.Skip(1))
{
if (list[index] != match)
{
return false;
}
}
return true;
}
Given for example:
List<List<int>> listOfLists = new List<List<int>>
{
new List<int> { 1, 100, 2},
new List<int> { 2, 100, 3},
new List<int> { 3, 100, 4},
new List<int> { 4, 100, 5},
};
So a List<> of List<int>
the totally unreadable LINQ expression that will return a List<bool> is something like:
List<bool> result = Enumerable.Range(0, listOfLists.Count != 0 ? listOfLists[0].Count : 0)
.Select(x => listOfLists.Count <= 1 ?
true :
listOfLists.Skip(1).All(y => y[x] == listOfLists[0][x])
).ToList();
Here I want to show you that if your first solution to any problem is LINQ, then perhaps now you will have two problems.
Now... What does this linq does? We have 4 List<int>, each one with 3 elements... So 3 rows of 4 columns. We want to calculate the result "by row", so the first thing is discover the number of rows, that is listOfLists[0].Count (we put a pre-check for the case that we have 0 rows). Now we generate an index (like a for), using Enumerable.Range(0, numberofrows), like for (int i = 0; i < numberofrows; i++). For each row we see if there are 0 or 1 columns (listOfLists.Count <= 1), then the result is true, otherwise we compare all the other columns y[x] with the first column listOfLists[0][x].
With a dual for cycle it becomes clearer probably:
var result2 = new List<bool>(listOfLists.Count != 0 ? listOfLists[0].Count : 0);
// Note the use of .Capacity here. It is listOfLists.Count != 0 ? listOfLists[0].Count : 0
for (int col = 0; col < result2.Capacity; col++)
{
if (listOfLists.Count <= 1)
{
result2.Add(true);
}
else
{
bool equal = true;
for (int row = 1; row < listOfLists.Count; row++)
{
if (listOfLists[row][col] != listOfLists[0][col])
{
equal = false;
break;
}
}
result2.Add(equal);
}
}
Note that both programs can be simplified: new int[0].All(x => something) == true, so .All() on empty IEnumerable<> is true. You can remove listOfLists.Count <= 1 ? true : and if (...) { ... } else up to the else keyword, keeping only the code inside the else:
var result2 = new List<bool>(listOfLists.Count != 0 ? listOfLists[0].Count : 0);
// Note the use of .Capacity here. It is listOfLists.Count != 0 ? listOfLists[0].Count : 0
for (int col = 0; col < result2.Capacity; col++)
{
bool equal = true;
for (int row = 1; row < listOfLists.Count; row++)
{
if (listOfLists[row][col] != listOfLists[0][col])
{
equal = false;
break;
}
}
result2.Add(equal);
}
Here you go
IEnumerable<bool> CompareAll<T>(IEnumerable<IEnumerable<T>> source)
{
var lists = source.ToList();
var firstList = lists[0];
var otherLists = lists.Skip(1).ToList();
foreach(var t1 in firstList)
{
yield return otherlists.All(tn => tn.Equals(t1));
}
}

How can I split an array into smaller arrays?

I want to take a list of names, add them to an array, then split that array into N groups, then display those arrays in separate textboxes in a Windows form. So far I have this, which takes the list and splits them up, but honestly, I don't think it's doing what I want it to do.
MasterList:
Johnny, Mark, Tom, Carl, Jenny, Susie, Ben, Tim, Angie
Group 1: Johnny, Mark, Angie
Group 2: Tom, Carl
Group 3: Jenny, Susie
Group 4: Ben, Tim
void addnamestoList_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(this.studentnameTboxContent))
{
int num = (int)MessageBox.Show("No content to format.",
"Message",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
else
{
transformText();
}
}
public void transformText()
{
string[] masterList = studentnameTboxContent.Split('\n');
var split = from index in Enumerable.Range(0, masterList.Length)
group masterList[index] by index / int.Parse(groupcountTboxContent);
studentNames.Text = "";
foreach (var Array in split)
{
studentNames.AppendText(string.Join(Environment.NewLine, Array.ToArray()));
}
}
Method to randomize list:
private string[] randomizeList(string[] list)
{
Random rnd = new Random();
string[] randomList = list.OrderBy(x => rnd.Next()).ToArray();
return randomList;
}
Here's one way to do it, but it isn't very elegant. Basically calculate the group size based on the group count entered by the user, determine how many items should be in each group, and determine the number of remaining items that need to be added to the first lists (if the group cannot be evenly divided by the count).
Then, in a loop, skip the number of items you've taken so far, then take the group size number of items, and if there are still extra items that need to be added, grab them from the end of the list:
var masterList = new List<string>
{
"Johnny", "Mark", "Tom", "Carl",
"Jenny", "Susie", "Ben", "Tim", "Angie"
};
var groupCount = 4; // Entered by the user
var minGroupSize = masterList.Count / groupCount;
var extraItems = masterList.Count % groupCount;
var groupedNames = new List<List<string>>();
for (int i = 0; i < groupCount; i++)
{
groupedNames.Add(masterList.Skip(i * minGroupSize).Take(minGroupSize).ToList());
if (i < extraItems)
{
groupedNames[i].Add(masterList[masterList.Count - 1 - i]);
}
}
Console.WriteLine("Here are the groups:");
for(int index = 0; index < groupedNames.Count; index++)
{
Console.WriteLine($"#{index + 1}: {string.Join(", ", groupedNames[index])}");
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
Output
This code can easily be extracted into a method so it can be re-used elsewhere:
static List<List<string>> GetGroups(List<string> masterList, int groupCount)
{
var groups = new List<List<string>>();
// Argument validation. All of these conditions should be true.
if (masterList != null && groupCount > 0 && groupCount <= masterList.Count)
{
var minGroupSize = masterList.Count / groupCount;
var extraItems = masterList.Count % groupCount;
for (int i = 0; i < groupCount; i++)
{
groups.Add(masterList.Skip(i * minGroupSize).Take(minGroupSize).ToList());
if (i < extraItems)
{
groups[i].Add(masterList[masterList.Count - 1 - i]);
}
}
}
return groups;
}
Usage
var masterList = new List<string>
{
"Johnny", "Mark", "Tom", "Carl", "Jenny",
"Susie", "Ben", "Tim", "Angie"
};
var groupedNames = GetGroups(masterList, 4);

Create a list of all permutation from different lists [duplicate]

This one should not be too hard but my mind seems to be having a stack overflow (huehue). I have a series of Lists and I want to find all permutations they can be ordered in. All of the lists have different lengths.
For example:
List 1: 1
List 2: 1, 2
All permutations would be:
1, 1
1, 2
In my case I don't switch the numbers around. (For example 2, 1)
What is the easiest way to write this?
I can't say if the following is the easiest way, but IMO it's the most efficient way. It's basically a generalized version of the my answer to the Looking at each combination in jagged array:
public static class Algorithms
{
public static IEnumerable<T[]> GenerateCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
{
var result = new T[input.Count];
var indices = new int[input.Count];
for (int pos = 0, index = 0; ;)
{
for (; pos < result.Length; pos++, index = 0)
{
indices[pos] = index;
result[pos] = input[pos][index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index >= input[pos].Count);
}
}
}
You can see the explanation in the linked answer (shortly it's emulating nested loops). Also since for performace reasons it yields the internal buffer w/o cloning it, you need to clone it if you want store the result for later processing.
Sample usage:
var list1 = new List<int> { 1 };
var list2 = new List<int> { 1, 2 };
var lists = new[] { list1, list2 };
// Non caching usage
foreach (var combination in lists.GenerateCombinations())
{
// do something with the combination
}
// Caching usage
var combinations = lists.GenerateCombinations().Select(c => c.ToList()).ToList();
UPDATE: The GenerateCombinations is a standard C# iterator method, and the implementation basically emulates N nested loops (where N is the input.Count) like this (in pseudo code):
for (int i0 = 0; i0 < input[0].Count; i0++)
for (int i1 = 0; i1 < input[1].Count; i1++)
for (int i2 = 0; i2 < input[2].Count; i2++)
...
for (int iN-1 = 0; iN-1 < input[N-1].Count; iN-1++)
yield { input[0][i0], input[1][i1], input[2][i2], ..., input[N-1][iN-1] }
or showing it differently:
for (indices[0] = 0; indices[0] < input[0].Count; indices[0]++)
{
result[0] = input[0][indices[0]];
for (indices[1] = 0; indices[1] < input[1].Count; indices[1]++)
{
result[1] = input[1][indices[1]];
// ...
for (indices[N-1] = 0; indices[N-1] < input[N-1].Count; indices[N-1]++)
{
result[N-1] = input[N-1][indices[N-1]];
yield return result;
}
}
}
Nested loops:
List<int> listA = (whatever), listB = (whatever);
var answers = new List<Tuple<int,int>>;
for(int a in listA)
for(int b in listB)
answers.add(Tuple.create(a,b));
// do whatever with answers
Try this:
Func<IEnumerable<string>, IEnumerable<string>> combine = null;
combine = xs =>
xs.Skip(1).Any()
? xs.First().SelectMany(x => combine(xs.Skip(1)), (x, y) => String.Format("{0}{1}", x, y))
: xs.First().Select(x => x.ToString());
var strings = new [] { "AB", "12", "$%" };
foreach (var x in combine(strings))
{
Console.WriteLine(x);
}
That gives me:
A1$
A1%
A2$
A2%
B1$
B1%
B2$
B2%
I made the following IEnumerable<IEnumerable<TValue>> class to solve this problem which allows use of generic IEnumerable's and whose enumerator returns all permutations of the values, one from each inner list. It can be conventiently used directly in a foreach loop.
It's a variant of Michael Liu's answer to IEnumerable and Recursion using yield return
I've modified it to return lists with the permutations instead of the single values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Permutation
{
public class ListOfListsPermuter<TValue> : IEnumerable<IEnumerable<TValue>>
{
private int count;
private IEnumerable<TValue>[] listOfLists;
public ListOfListsPermuter(IEnumerable<IEnumerable<TValue>> listOfLists_)
{
if (object.ReferenceEquals(listOfLists_, null))
{
throw new ArgumentNullException(nameof(listOfLists_));
}
listOfLists =listOfLists_.ToArray();
count = listOfLists.Count();
for (int i = 0; i < count; i++)
{
if (object.ReferenceEquals(listOfLists[i], null))
{
throw new NullReferenceException(string.Format("{0}[{1}] is null.", nameof(listOfLists_), i));
}
}
}
// A variant of Michael Liu's answer in StackOverflow
// https://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return
public IEnumerator<IEnumerable<TValue>> GetEnumerator()
{
TValue[] currentList = new TValue[count];
int level = 0;
var enumerators = new Stack<IEnumerator<TValue>>();
IEnumerator<TValue> enumerator = listOfLists[level].GetEnumerator();
try
{
while (true)
{
if (enumerator.MoveNext())
{
currentList[level] = enumerator.Current;
level++;
if (level >= count)
{
level--;
yield return currentList;
}
else
{
enumerators.Push(enumerator);
enumerator = listOfLists[level].GetEnumerator();
}
}
else
{
if (level == 0)
{
yield break;
}
else
{
enumerator.Dispose();
enumerator = enumerators.Pop();
level--;
}
}
}
}
finally
{
// Clean up in case of an exception.
enumerator?.Dispose();
while (enumerators.Count > 0)
{
enumerator = enumerators.Pop();
enumerator.Dispose();
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
You can use it directly in a foreach like this:
public static void Main(string[] args)
{
var listOfLists = new List<List<string>>()
{
{ new List<string>() { "A", "B" } },
{ new List<string>() { "C", "D" } }
};
var permuter = new ListOfListsPermuter<string>(listOfLists);
foreach (IEnumerable<string> item in permuter)
{
Console.WriteLine("{ \"" + string.Join("\", \"", item) + "\" }");
}
}
The output:
{ "A", "C" }
{ "A", "D" }
{ "B", "C" }
{ "B", "D" }

How to check whether a word is composed of other strings in an array

I want to check whether a string is built from another two strings within a given string set.
For example, given the following array:
var arr = new string[] { "b", "at", "bat", "ct", "ll", "ball", "ba"};
I want to return only "bat" and "ball".
That's because they can be composed from two other elements in the array like so:
"bat" = "b" + "at"
"ball" = "ba" + "ll"
I have tried doing it with a foreach loop, but I'm not quite getting it right.
Any help will be much appreciated.
I have done something like
foreach(var x in list)
{
if (dataaccess.IsThreeCharacters(x))
{
for (int i = 0; i < arr.Length; i++)
{
for (int j = i; j < arr.Length; j++)
{
if(x == arr[i] + arr[j])
{
newlist.Add(x);
}
}
}
}
}
This will give you all of the values that can be composed from other values in the sequence:
var values = new HashSet<string>(new[] { "b", "at", "bat", "ct", "ll", "ball", "ba" });
var compositeValues =
from value in values
from otherValue in values
where value != otherValue
let compositeValue = value + otherValue
where values.Contains(compositeValue)
select compositeValue;
Notice the use of HashSet<string>, which gives O(1) lookup performance, as opposed to the O(N) of an array.
This should work although I'm not vouching for efficiency!
static void Main(string[] args)
{
var arr = new string[] { "b", "at", "bat", "ct", "ll", "ball", "ba" };
var composites = from s in arr
from lhs in arr
from rhs in arr
where s == string.Concat(lhs, rhs)
select s;
foreach (var composite in composites)
{
Console.WriteLine(composite);
}
Console.ReadLine();
}

Categories