Merging arrays with common element - c#

I want to merge arrays with common element. I have list of arrays like this:
List<int[]> arrList = new List<int[]>
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 2, 7 },
new int[] { 8, 9 },
new int[] { 10, 11, 12 },
new int[] { 3, 9, 13 }
};
and I would like to merge these arrays like this:
List<int[]> arrList2 = new List<int[]>
{
new int[] { 1, 2, 7 },
new int[] { 10, 11, 12 },
new int[] { 3, 4, 5, 8, 9, 13 } //order of elements doesn't matter
};
How to do it?

Let each number be a vertex in the labelled graph. For each array connect vertices pointed by the numbers in the given array. E.g. given array (1, 5, 3) create two edges (1, 5) and (5, 3). Then find all the connected components in the graph (see: http://en.wikipedia.org/wiki/Connected_component_(graph_theory))

I'm pretty sure it is not the best and the fastest solution, but works.
static List<List<int>> Merge(List<List<int>> source)
{
var merged = 0;
do
{
merged = 0;
var results = new List<List<int>>();
foreach (var l in source)
{
var i = results.FirstOrDefault(x => x.Intersect(l).Any());
if (i != null)
{
i.AddRange(l);
merged++;
}
else
{
results.Add(l.ToList());
}
}
source = results.Select(x => x.Distinct().ToList()).ToList();
}
while (merged > 0);
return source;
}
I've used List<List<int>> instead of List<int[]> to get AddRange method available.
Usage:
var results = Merge(arrList.Select(x => x.ToList()).ToList());
// to get List<int[]> instead of List<List<int>>
var array = results.Select(x => x.ToArray()).ToList();

Use Disjoint-Set Forest data structure. The data structure supports three operations:
MakeSet(item) - creates a new set with a single item
Find(item) - Given an item, look up a set.
Union(item1, item2) - Given two items, connects together the sets to which they belong.
You can go through each array, and call Union on its first element and each element that you find after it. Once you are done with all arrays in the list, you will be able to retrieve the individual sets by going through all the numbers again, and calling Find(item) on them. Numbers the Find on which produce the same set should be put into the same array.
This approach finishes the merge in O(α(n)) amortized (α grows very slowly, so for all practical purposes it can be considered a small constant).

Related

Check if all elements from one array are in the second array c#

How can I check if all the elements from one array are in another array? I have a 2d array with 3 arrays in it,and I want to check all of those 3 arrays if they have all the elements from allnumbers. array1=allnumbers ? array2=allnumbers ? array1=allnumber2 ? I need to return true if at least one contains all the elements from allnumbers. I have the code bellow,but I need it not to contain more than 3 control flow statements.
// int[,][] array = {array1, array2, array3}
static bool CheckLine(int[,][] array)
{
const int maxL = 9;
bool result = false;
int[] allnumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var singlearray in array)
{
int[] arr = singlearray;
int p = 0;
foreach (var num in allnumbers)
{
foreach (var arraynumber in singlearray)
{
if (arraynumber == num)
{
p++;
}
}
if (p == maxL)
{
result = true;
break;
}
}
}
return result;
}
If the values in your array are unique, and you don't care about the order they're in, this is a job for HashSet. (In other words, if your arrays contain sets of numbers you can treat them as sets.) Here's the basic outline of comparing sets.
var allnumbersSet = new HashSet<int>(allnumbers);
var allnumbers2Set= new HashSet<int>(allnumbers2);
if (allnumbersSet.IsSupersetOf(allnumbers2Set)) {
/* everything in allnumbers2 is also in allnumbers1 */
}
The people who put together DotNet did a really good job creating and optimizing those collection classes; you can use them with confidence to get good performance.
It seems, that you have two-dimensional jagged array. You can simplify your code by using Except and check the difference between allnumbers array and single row at every loop iteration.
static bool CheckLine(int[,][] array)
{
int[] allnumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var singlearray in array)
{
var diff = allnumbers.Except(singlearray);
if (!diff.Any())
{
return true;
}
}
return false;
}
If there is no elements in a difference, it'll mean that single item from source 2D array has all elements from allnumbers array.
Example of the usage
var array = new int[2, 2][];
array[0, 0] = new[] { 1, 2, 8 };
array[0, 1] = new[] { 3, 4, 5, 6 };
array[1, 1] = new[] { 3, 2, 1, 4, 5, 7, 6, 10, 9, 8 };
array[1, 0] = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
CheckLine(array);
The last two items satisfy the condition, execution will break and return true for { 3, 2, 1, 4, 5, 7, 6, 10, 9, 8 } array. Also don't forget to add using System.Linq directive at the top of file
Thank you for your help. I forgot to mention that I can use only "using System;"

Summing up a list of integer arrays using threads for each array in C# Console application

I have a List of int arrays. The list can be from 1 to 4 arrays.
I want to know how do i go about summing each array with individual threads and
placing the summed values into a new int array.
If the order of the new array is not important here you have a example
List<int[]> arraysList = new List<int[]>();
arraysList.Add(new int[] { 2, 3, 5 });
arraysList.Add(new int[] { 2, 3, 5, 9, 123, 5 });
arraysList.Add(new int[] { 3 });
arraysList.Add(new int[] { 9,8 });
ConcurrentBag<int> SummedValueOfEveryArray = new ConcurrentBag<int>();
Parallel.ForEach(arraysList, array =>
{
SummedValueOfEveryArray.Add(array.Sum());
});
//Your result
var result = SummedValueOfEveryArray.ToArray<int>();
//The sum of all arrays
var totalSum = SummedValueOfEveryArray.Sum();
This code will do what you ask. One side note however, this only parallelizes when .Net feels it could improve performance.
List<int[]> intlist = new List<int[]>();
int[] result = intlist.AsParallel().Select(arr => arr.Sum()).ToArray();
Given 1 to 4 arrays it may be that .Net never sees the point of parallelizing. But if you absolutely must you can force parallelization by using Parallel.For as shown below.
List<int[]> intlist = new List<int[]>();
int[] result = new int[intlist.Count];
Parallel.For(0, intlist.Count, i =>
{
result[i] = intlist[i].Sum();
});

How to access and re-format Jagged Array in C#

I have 2D array in c#, like this:
int[][] 2darray = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
how can I get one column as normal array, like
int[] array = 2darray[1][]; //example, not working
and have
int[] array = {3,4};
?
Thanks.
There are several reasons why your code can't compile
This way it works:
int[][] array2d = { new[]{ 1, 2 }, new[]{ 3, 4 }, new[]{ 5, 6 }, new[]{ 7, 8 } };
int[] array = array2d[0];
Problems:
2darray is not a valid variable name
The indexing is wrong
The initialization of the original array is wrong
EDIT:
As stated by #heltonbiker, if you require all elements of the first column, you can use this:
int[] col = array2d.Select(row => row[0]).ToArray();
For an array with two columns and four rows, you can use LINQ this way:
using System.Linq;
first_column = _2darray.Select(row => row[0]).ToArray();
Note that changing the first or second array will not change the other one.
You are confusing jagged arrays and multidimensional arrays in C#. While they are similar, there is a slight difference. Rows in a jagged array can have a different number of elements, while in a 2D-array they are of the same length. Therefore when working with jagged arrays you need to remember to write handling for a missing column element. I composed a sample console app below to show how both of them work - it uses 0 as a substitute for a missing element, but you can throw an error etc.:
using System.Collections.Generic;
namespace JaggedArrayExample
{
class Program
{
static void Main(string[] args)
{
//jagged array declaration
int[][] array1;
//jagged array declaration and assignment
var array2 = new int[][] {
new int[] { 1, 2 },
new int[] { 3, 4 },
new int[] { 5, 6 },
new int[] { 7, 8 }
};
//2D-array declaration
int[,] array3;
//2D-array declaration and assignment (implicit bounds)
var array4 = new int[,] {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
//2D-array declaration and assignment (explicit bounds)
var array5 = new int[4, 2] {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
//get rows and columns at index
var r = GetRow(array2, 1); //second row {3,4}
var c = GetColumn(array2, 1); //second column {2,4,6,8}
}
private static int[] GetRow(int[][] array, int index)
{
return array[index]; //retrieving the row is simple
}
private static int[] GetColumn(int[][] array, int index)
{
//but things get more interesting with columns
//especially if jagged arrays are involved
var retValue = new List<int>();
foreach (int[] r in array)
{
int ub = r.GetUpperBound(0);
if (ub >= index) //index within bounds
{
retValue.Add(r[index]);
}
else //index outside of bounds
{
retValue.Add(0); //default value?
//or you can throw an error
}
}
return retValue.ToArray();
}
}
}
try this, it should work
int[] array = array2d[1];
Change the name of the variable to array2d, you cannot have variable that starts with number, a variable can start with letter or underscore.

comparing two lists and removing missing numbers with C#

there are two lists:
List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });
how do you compare two lists, find missing numbers in List1 and remove these numbers from List1? To be more precise, I need to find a way to specify starting and ending position for comparison.
I imagine that the proccess should be very similar to this:
Step 1.
int start_num = 3; // we know that comparisons starts at number 3
int start = list2.IndexOf(start_num); // we get index of Number (3)
int end = start + 2; // get ending position
int end_num = list2[end]; // get ending number (6)
now we've got positions of numbers (and numbers themselves) for comparison in List2 (3,5,6)
Step 2. To get positions of numbers in List1 for comparison - we can do the following:
int startlist1 = list1.IndexOf(start_num); // starting position
int endlist1 = list1.IndexOf(end_num); // ending position
the range is following: (3,4,5,6)
Step 3. Comparison. Tricky part starts here and I need a help with it
Basically now we need to compare list2 at (3,5,6) with list1 at (3,4,5,6). The missing number is "4".
// I have troubles with this step but the result will be:
int remove_it = 4; // or int []
Step 4. Odd number removal.
int remove_it = 4;
list1 = list1.Where(a => a != remove_it).ToList();
works great, but what will happen if we have 2 missing numbers? i.e.
int remove_it = 4 // becomes int[] remove_it = {4, 0}
Result As you have guessed the result is new List1, without number 4 in it.
richTextBox1.Text = "" + string.Join(",", list1.ToArray()); // output: 0,1,2,3,5,6
textBox1.Text = "" + start + " " + start_num; // output: 2 3
textBox3.Text = "" + end + " " + end_num; // output: 4 6
textBox2.Text = "" + startlist1; // output: 3
textBox4.Text = "" + endlist1; // output: 6
Can you guy help me out with Step 3 or point me out to the right direction?
Also, can you say what will happen if starting number(start_num) is the last number, but I need to get next two numbers? In example from above numbers were 3,5,6, but they should be no different than 5,6,0 or 6,0,1 or 0,1,2.
Just answering the first part:
var list3 = list1.Intersect(list2);
This will set list3 to { 0, 1, 2, 3, 4, 5, 6 } - { 0, 4 } = { 1, 2, 3, 5, 6 }
And a reaction to step 1:
int start_num = 3; // we know that comparisons starts at number 3
int start = list2.IndexOf(start_num); // we get index of Number (3)
int end = start + 2; // get ending position
From where do you get all those magic numbers (3, + 2 ) ?
I think you are over-thinking this, a lot.
var result = list1.Intersect(list2)
You can add a .ToList on the end if you really need the result to be a list.
List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });
// find items in list 2 notin 1
var exceptions = list1.Except(list2);
// or are you really wanting to do a union? (unique numbers in both arrays)
var uniquenumberlist = list1.Union(list2);
// or are you wanting to find common numbers in both arrays
var commonnumberslist = list1.Intersect(list2);
maybe you should work with OrderedList instead of List...
Something like this:
list1.RemoveAll(l=> !list2.Contains(l));
To get the numbers that exist in list1 but not in list2, you use the Except extension method:
IEnumerable<int> missing = list1.Except(list2);
To loop through this result to remove them from list1, you have to realise the result, otherwise it will read from the list while you are changing it, and you get an exception:
List<int> missing = list1.Except(list2).ToList();
Now you can just remove them:
foreach (int number in missing) {
list1.Remove(number);
}
I'm not sure I understand your issue, and I hope the solution I give you to be good for you.
You have 2 lists:
List list2 = new List(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4
List list1 = new List(new[] { 0, 1, 2, 3, 4, 5, 6 });
To remove from list1 all the missing numbers in list2 I suggest this solution:
Build a new list with missing numbers:
List diff = new List();
then put all the numbers you need to remove in this list. Now the remove process should be simple, just take all the elements you added in diff and remove from list2.
Did I understand correctly that algorithm is:
1) take first number in List 2 and find such number in List1,
2) then remove everything from list 1 until you find second number form list2 (5)
3) repeat step 2) for next number in list2.?
You can use Intersect in conjunction with Skip and Take to get the intersection logic combined with a range (here we ignore the fact 0 is missing as we skip it):
static void Main(string[] args)
{
var list1 = new List<int> { 1, 2, 3, 4, 5 };
var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };
foreach (var i in list2.Skip(3).Take(3).Intersect(list1))
Console.WriteLine(i); // Outputs 3 then 5.
Console.Read();
}
Though if I'm being really honest, I'm not sure what is being asked - the only thing I'm certain on is the intersect part:
var list1 = new List<int> { 1, 2, 3, 4, 5 };
var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };
foreach (var i in list2.Intersect(list1))
Console.WriteLine(i); // Outputs 1, 2, 3, 5.
ok, seems like I hadn't explained the problem well enough, sorry about it. Anyone interested can understand what I meant by looking at this code:
List<int> list2 = new List<int>() { 1, 2, 3, 5, 6 }; // missing: 0 and 4
List<int> list1 = new List<int>() { 0, 1, 2, 3, 4, 5, 6 };
int number = 3; // starting position
int indexer = list2.BinarySearch(number);
if (indexer < 0)
{
list2.Insert(~index, number); // don't look at this part
}
// get indexes of "starting position"
int index1 = list1.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;
int index2 = list2.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;
// reorder lists starting at "starting position"
List<int> reorderedList1 = list1.Skip(index1).Concat(list1.Take(index1)).ToList(); //main big
List<int> reorderedList2 = list2.Skip(index2).Concat(list2.Take(index2)).ToList(); // main small
int end = 2; // get ending position: 2 numbers to the right
int end_num = reorderedList2[end]; // get ending number
int endlist1 = reorderedList1.IndexOf(end_num); // ending position
//get lists for comparison
reorderedList2 = reorderedList2.Take(end + 1).ToList();
reorderedList1 = reorderedList1.Take(endlist1 + 1).ToList();
//compare lists
var list3 = reorderedList1.Except(reorderedList2).ToList();
if (list3.Count != 0)
{
foreach (int item in list3)
{
list1 = list1.Where(x => x != item).ToList(); // remove from list
}
}
// list1 is the result that I wanted to see
if there are any ways to optimize this code please inform me. cheers.

remove a value from an int array c#

I have an array of int values int[] ids.
I have a Datatable DataTable dt
I want to keep only those values in the array that are there in the Datatable column ids
Say int[] ids contain [2,3,4,5]
dt contains [2,3,4,3,4] ---ids here may repeat
so output ids will have only [2,3,4]
Pls suggest ways with lambda or linq....
I tried the crude way using two foreachs.
use
int[] myIDs = (from d in dt.AsEnumerable() select d.Field<int>("id")).Intersect (ids).ToArray();
For reference see:
http://msdn.microsoft.com/en-us/library/bb360891.aspx
http://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable.aspx
http://msdn.microsoft.com/en-us/library/bb460136.aspx
http://msdn.microsoft.com/en-us/library/x303t819.aspx
http://msdn.microsoft.com/en-us/vcsharp/aa336746
http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#intersect1
You need to create a new array.
Arrays are fixed size.
If you want a data structure able to remove an element you need a List.
Note that List removal operation have a worst case complexity of O(n).
For your particular problem however i would write something like this:
public int[] MyFunc(DataTable dt, int[] array)
{
Set<int> allowedsIds = new Set<int>();
Fill your set with ids you want to keep
int[] newArray = new int[inputArray.Length];
int newArrayCount = 0;
for (int i = 0; i < inputArray.Length; ++i)
{
if (allowedsIds.Contains(inputArray[i]))
{
newArray[newArrayCount++] = inputArray[i];
}
}
Array.Resize(ref newArray, newArrayCount);
return newArray;
}
You need the intersection of the 2 collections. Linq as a Intersect method for that.
From the Linq 101 samples:
public void Linq50()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var commonNumbers = numbersA.Intersect(numbersB);
Console.WriteLine("Common numbers shared by both arrays:");
foreach (var n in commonNumbers)
{
Console.WriteLine(n);
}
}
You can find more examples here in Linq 101 Samples.
Use the Intersect function:
var ids = new[] {2, 3, 4, 5};
var dt = new[] {2, 3, 4, 3, 4};
foreach (var id in ids.Intersect(dt))
{
}
You could create List<int> fromDB and (cycling over dataset) fill it with ids column values.
Then you could use:
List<int> result = ids.Intersect(fromDB).ToList();

Categories