Unable to find intersection of two array - c#

I have one array int[] com which contains two values 0 and 1 (at initial stage).
I define one more array as String[] arr = new String[100];
arr contains 6 elements which are:
arr[0]={4,8,10,11,12,14}
arr[1]={1,2,3,4,8,12,14}
.. arr[6]=something
I want to find intersection of arr[0] and arr[1], so I wrote the code as:
foreach (int value1 in intersect)
{
//perform logic
}
Here I should get value1 as 4,8 but i am getting value1 as 52,44.
What is wrong with what I am doing?

Ok here is what you are doing, you have string arrays not int arrays. If you do this
arr[0]="4,8,10,11,12,14";
arr[1]="1,2,3,4,8,12,14";
var intersection = arr[0].Intersect(arr[1]);
since arr[0] and arr[1] are strings, you'll get as the result this list of chars '4', ',' , '8', '1', '2' which corresponds respectively to the integer values 52 44 56 49 50 which is exactly what you are getting.
You should declare integer matrix instead of array of strings int [,] arr = new int[100,100]; or even better List<List<int>>. You can't use integers like strings, at least not in this context.
List<List<int>> arr = new List<List<int>>();
arr.Add(new List<int>{4,8,10,11,12,14});
arr.Add(new List<int>{1,2,3,4,8,12,14});
var intersection = arr[0].Intersect(arr[1]);
But if you don't believe me, and want to be sure that your previous code doesn't make sense, change the foreach loop and see what's happening:
foreach (char value1 in intersect)
{
//perform logic
}
In addition, you don't need to do this:
int zero= Convert.ToInt32(com[0].ToString());
int one= Convert.ToInt32(com[1].ToString());
You could replace it with something like:
int zero= com[0];
int one = com[1];
but nevertheless it's pointless since you can do this:
arr[com[0]]
arr[com[1]]

The LINQ Intersect method correctly computes the intersection between arrays:
var a = new [] {4,8,10,11,12,14};
var b = new [] {1,2,3,4,8,12,14};
var intersection = a.Intersect(b);
// intersection:
// IEnumerable<int> { 4, 8, 12, 14 }
The above code - which represents a minimum non-failing counter example - was run in LINQPad.
Note that Intersect relies on Equals, so it's possible to "break" it:
var a = new object[] {4,8,10,11,12,14};
var b = new object[] {"1","2","3","4","8","12","14"};
var intersection = a.Intersect(b);
// intersection:
// IEnumerable<object> { }
Of course, this doesn't account for "random new values" - that's just a bug elsewhere.

Related

Sort List According To The Numbers in Each Element

I tried to solve a problem few days ago and almost solved with the help of SO. Unfortunately stuck into a situation that am unable to sort out. Here's the scenario:
Input:
[7, "aaa", "a", "cccccccccc", 5]
Output:
["a", "aaa", 5, 7, "cccccccccc"]
So you can see depending upon the number of letters in the element, the array should be sorted. In case of number, that should be sorted as well. At one point, the below code worked:
//Dynamic list where we can have string and integers
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
int val;
//What I did here, converted all items into string
//Checks if the list contains string
var letters = aLst.Where(i => !int.TryParse(i.ToString(), out val)).OrderBy(i => i.Length).ToList();
//Checks if the list contains number
var numbers = aLst.Where(i => int.TryParse(i.ToString(), out val)).OrderBy(i => int.Parse(i.ToString())).ToList();
//Finally from the number result set, taking the numbers to get their indexes and set them into the list accordingly
foreach (var number in numbers)
{
//Checks number index
var index = int.Parse(number.ToString());
if (letters.Count() >= index)
{
letters.Insert(index, number); //Assign index to numbers
}
else
{
letters.Insert(number);
}
}
foreach(var value in letters)
{
Console.WriteLine(value);
}
The above code gets me the expected result. But when the input is something as follows, it returns different result set that I can't able to set accordingly:
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(10);
aLst.Add(5);
aLst.Add("cccccc");
aLst.Add("cccccccccccc");
The result I get:
["a", 2, "aa", "aaa", 5, "cccc", 7, "cccccc", "cccccccccccc", 10]
Expected output:
["a", 2, "aa", "aaa", "cccc", 5, "cccccc", 7, 10, "cccccccccccc"]
Anything that I am doing wrong here or missed something? Any idea would be appreciated.
Code snippet: Sort Array Elements
The key here is to check the type of the object. If is a string, use the string's length for the order, otherwise assume it is an int and use the value itself for the order.
This will throw an exception if there are something else in the object list, for example an instance of some random class.
var list = new List<object> { 7, "aaa", "a", "cccccccccc", 5 };
// this assumes the elements in the array above (which can be anything) are only strings or integer
var ordered = list.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
// print array to see results
Console.WriteLine(string.Join(",", ordered));
I hope i understood your sorting intension correctly. You could use a custom comparer to isolate the comparison logic which could check if it is a string or a number. For example,
public class Comparer : IComparer<object>
{
public int Compare(object a, object b)
{
var valA = GetValue(a);
var valB = GetValue(b);
return valA.CompareTo(valB);
}
private int GetValue(object ch)
{
if(Int32.TryParse(ch.ToString(),out var val))
return val;
else
return ch.ToString().Length;
}
}
You could now use the Custom comparer with Linq easily.
var output = list.OrderBy(x=>x, new Comparer())
Note that this assumes you are dealing with strings and numbers only. If you need to include other types, you could include the required logic within the Custom Comparer
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
for (int i = 0; i < aLst.Count; i++)
{
if (aLst[i] is int val)
{
aLst.RemoveAt(i);
aLst.Insert(0, val);
}
}
//var ty = aLst.Select(x => x.ToString());
var ordered = aLst.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
Console.WriteLine(string.Join(",", ordered)); //a,2,aa,aaa,cccc,5,cccccc,7

Sort two dimensional array with different lengths

Hi fellow programmers,
I am trying to sort a two dimensional array. This array represent a collection of objects which has a property which have a value in the list underneath. So the original list does not have to be saved.
The starting situation is:
var list = new List<string>
{
"10-158-6",
"11-158-6",
"90-158-6",
"20-15438-6",
"10-158-6",
"10-158-6-3434",
"10-1528-6"
};
The result should be
var list = new List<string>
{
"10-158-6",
"10-158-6",
"10-1528-6"
"10-158-6-3434",
"11-158-6",
"20-15438-6",
"90-158-6",
};
It should be first ordered on the first part -> then the second -> etc. etc.
I think it is almost impossible to sort these strings so I converted it to a two-dimensional list. I found different solutions to sort multi dimensional list but none can be used for this problem. Also I do not have a clue where to start...
Anyone has an idea how to write a sorting algorithm that doesn't have unnecessary huge big O?
Thanks in advance!
Jeroen
You can use Sort method; let's implement a general case with arbitrary long numbers:
Code:
var list = new List<string>() {
"10-158-6",
"11-158-6",
"90-158-6",
"20-15438-6",
"10-158-6",
"10-158-6-3434",
"10-1528-6",
"123456789012345678901234567890"
};
list.Sort((left, right) => {
var x = left.Split('-');
var y = right.Split('-');
// Compare numbers:
for (int i = 0; i < Math.Min(x.Length, y.Length); ++i) {
// Longer number is always bigger: "123" > "99"
int r = x[i].Length.CompareTo(y[i].Length);
// If numbers are of the same length, compare lexicographically: "459" < "460"
if (r == 0)
r = string.CompareOrdinal(x[i], y[i]);
if (r != 0)
return r;
}
// finally, the more items the bigger: "123-456-789" > "123-456"
return x.Length.CompareTo(y.Length);
});
// Let's have a look at the list after the sorting
Console.Write(string.Join(Environment.NewLine, list));
Outcome:
10-158-6
10-158-6
10-158-6-3434 // <- please, note that since 158 < 1528
10-1528-6 // <- "10-158-6-3434" is before "10-1528-6"
11-158-6
20-15438-6
90-158-6
123456789012345678901234567890
Those look like Version number. If a change from Dash to Dot are not a big change you can simply use C# Version
var list = new List<string>
{
"10-158-6",
"11-158-6",
"90-158-6",
"20-15438-6",
"10-158-6",
"10-158-6-3434",
"10-1528-6"
};
var versions = list.Select(x => new Version(x.Replace('-','.'))).ToList();
versions.Sort();
LiveDemo

Add two list data into array while using if condition

I have two lists, one list have some record (not known specific no of rec, but not more than 13 records) and second list have only empty value. I am using if condition on these two list. And want to add these two list in one array. I am using this code:
for (int i=0; i>12; i++)
{
List<string> excList = new List<string>();
//added column from table, which can varies
excList.Add((string)column.ColumnName);
string[] excelList = new string[] { };
List<string> stack = Enumerable.Range(excList.Count, 13)
.Select(z => string.Empty)
.ToList<string>();
if (excList.Count > i)
{
excelList = excList.ToArray();
}
if (excList.Count <= i)
{
excelList = stack.ToArray();
}
eCol0 = excelList[0].ToString();
//show first value, after adding two list in excelList
response.Write(eCol0);
}
Using this code, when the second condition started and list (excList) is adding in array (excelList) then excelList is showing only second list data.
I want to insert these two list (excList and stack) into arrayList (which have range of 13).But these two list must add on the bases of if condition as I'm using if condition in above code.
Well you never Add something to your string array excelList. You always assign it new.
Using an array is also not the best for adding values, since you need to know beforehand the size of the array.
If you really want an array in the end with both results, you should do something like this:
List<string> excList = new List<string>();
... fill your excList here and initialize the stack list with whatever you need ...
excList.AddRange(stack);
string[] excelList = excList.ToArray();
Edit: as the comments mention, your question is a little bit confusing and you are using one big loop with no clear reason why and adding empty values makes no sence too... so i tried to get the essence out of what you wanted to know
Edit:2
Wait a second, I think you want in the end, an array of strings, with the size of 13, where the elements are at least string.empty
List<string> excList = new List<string>();
//added column from table, which can varies
excList.Add((string)column.ColumnName);
string[] excelList = new string[13];
for (int i = 0; i < excList.Count; i++)
{
excelList[i] = excList[i];
}
for (int i = excList.Count; i < 13; i++)
{
excelList[i] = string.Empty;
}
no outer loop necessary
You've written a huge amount of confusing code that could be considerably more compact.
Through th commnts I was able to understand that you have a list of N strings, where N could be between 1 and 13, and you want to turn it into an array of 13 strings with all your list items at the start, and empty strings at the end
So a list of:
"a", "b", "c"
Becomes an array of:
"a", "b", "c", "", "", "", "", "", "", "", "", "", ""
If you want a one liner to generate you a list of 13 strings, from a List x of up to 13 strings:
string[] arrayOf13 = x.AddRange(Enumerable.Repeat("", 13 - x.Count)).ToArray();
If your list x will have an unknown number more than 13:
string[] arrayOf13 = x.AddRange(Enumerable.Repeat("", 13)).Take(13).ToArray();
Or without LINQ using either a for or a while loop:
for(; x.Count < 13; x.Add(""))
string[] arrayOf13 = x.ToArray();
while(x.Count < 13)
x.Add(""));
string[] arrayOf13 = x.ToArray();
If you're willing to have the strings be null rather than empty, you can just declare an array of size 13 (all null) and then use Array.CopyTo():
string[] arrayOf13 = new string[13];
x.ToArray().CopyTo(arrayOf13, 0);
It seems your goal is to get an array of 13 strings (excelList), where each element is eigher string.Empty by default or the corresponding (same index) element from some source list (excList).
So a short-code solution would be to first create a 13-element array, initialized with 'string.Empty' and then copy the source lists elements over, limited to max 13 elements:
var excelList = Enumerable.Repeat(string.Empty, 13).ToArray();
excList.CopyTo(0, excelList, 0, Math.Min(13, excList.Count));

Changing the order of a string based on an array of numbers in C#

Thanks for the help with my question about making an array of booleans into a string. The code is now working good. Now I have another problem. Maybe somebody would like to try. I think I could come up with a solution but if so I'm 99 percent sure that it would be not so simple as the answers I have seen from people here.
What I have is the string "ABD" from my question here. I also have an array of integers. For example [0] = 2, [1] = 3 and [2] = 1. I would like to find a way to apply this to my string to reorder the string so that the string changes to BDA.
Can anyone think of a simple way to do this?
If those integers are 1-based indices within the string (i.e. 2 = 2nd character), then you could do this:
string s = "ABD";
int[] oneBasedIndices = new [] { 2, 3, 1 };
string result = String.Join(String.Empty, oneBasedIndices.Select(i => s[i-1]));
NB: If you are using a version less than C# 4.0, you need to put a .ToArray() on the end of the select.
What this is doing is going through your int[] and with each int element picking the character in the string at that position (well -1, as the first index in an array is 0, but your example starts at 1).
Then, it has to do a String.Join() to turn that collection of characters back into a String.
As an aside, I'd recommend downloading LINQPad (no connection) - then you can just paste that code in there as a C# Program, and at any point type variable.Dump(); (e.g. result.Dump(); at the end) and see what the value is at that point.
First make a copy of the string. The copy will never change; it serves as your reference to what the values used to be.
Then loop through the original string one character at a time using a for loop. The counter in the for loop is the position of which character in the original string we are replacing next. The counter is also the index into the array to look up the position in the original string. Then replace the character at that position in the original string with the character from the copied string.
string orig = "ABD";
int[] oneBasedIndices = new [] { 2, 3, 1 };
string copy = orig;
for ( int i = 0; i < orig.Length; i++ )
{
orig[i] = copy[ oneBasedIndices[i] - 1 ];
}
There you have it. If the indices are zero based, remove the - 1.
Napkin code again...
string result = "ABD"; // from last question
var indecies = new []{ 1,2,0 };
string result2 = indecies.Aggregate(new StringBuilder(),
(sb, i)=>sb.Append(result[i]))
.ToString();
or a different version (in hopes of redeeming myself for -1)
StringBuilder sb = new StringBuilder();
for(int i = 0; i < indecies.Length; i++)
{
sb.Append(result[i]); // make [i-1] if indecies are 1 based.
}
string result3 = sb.ToString();

How do I sum a list<> of arrays

I have a List< int[] > myList, where I know that all the int[] arrays are the same length - for the sake of argument, let us say I have 500 arrays, each is 2048 elements long. I'd like to sum all 500 of these arrays, to give me a single array, 2048 elements long, where each element is the sum of all the same positions in all the other arrays.
Obviously this is trivial in imperative code:
int[] sums = new int[myList[0].Length];
foreach(int[] array in myList)
{
for(int i = 0; i < sums.Length; i++)
{
sums[i] += array[i];
}
}
But I was wondering if there was a nice Linq or Enumerable.xxx technique?
Edit: Ouch...This became a bit harder while I wasn't looking. Changing requirements can be a real PITA.
Okay, so take each position in the array, and sum it:
var sums = Enumerable.Range(0, myList[0].Length)
.Select(i => myList.Select(
nums => nums[i]
).Sum()
);
That's kind of ugly...but I think the statement version would be even worse.
EDIT: I've left this here for the sake of interest, but the accepted answer is much nicer.
EDIT: Okay, my previous attempt (see edit history) was basically completely wrong...
You can do this with a single line of LINQ, but it's horrible:
var results = myList.SelectMany(array => array.Select(
(value, index) => new { value, index })
.Aggregate(new int[myList[0].Length],
(result, item) => { result[item.index] += value; return result; });
I haven't tested it, but I think it should work. I wouldn't recommend it though. The SelectMany flattens all the data into a sequence of pairs - each pair is the value, and its index within its original array.
The Aggregate step is entirely non-pure - it modifies its accumulator as it goes, by adding the right value at the right point.
Unless anyone can think of a way of basically pivoting your original data (at which point my earlier answer is what you want) I suspect you're best off doing this the non-LINQ way.
This works with any 2 sequences, not just arrays:
var myList = new List<int[]>
{
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
new int[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 }
};
var sums =
from array in myList
from valueIndex in array.Select((value, index) => new { Value = value, Index = index })
group valueIndex by valueIndex.Index into indexGroups
select indexGroups.Select(indexGroup => indexGroup.Value).Sum()
foreach(var sum in sums)
{
Console.WriteLine(sum);
}
// Prints:
//
// 11
// 22
// 33
// 44
// 55
// 66
// 77
// 88
// 99
OK, assuming we can assume that the sum of the ints at each position over the list of arrays will itself fit into an int (which is a dodgy assumption, but I'll make it anyway to make the job easier):
int[] sums =
Enumerable.Range(0, listOfArrays[0].Length-1).
Select(sumTotal =>
Enumerable.Range(0, listOfArrays.Count-1).
Aggregate((total, listIndex) =>
total += listOfArrays[listIndex][sumTotal])).ToArray();
EDIT - D'oh. For some reason .Select evaded me originally. That's a bit better. It's a slight hack because sumTotal is acting as both the input (the position in the array which is used in the Aggregate call) and the output sum in the resulting IEnumerable, which is counter-intuitive.
Frankly this is far more horrible than doing it the old-fasioned way :-)
Here is one that trades the Linq statement simplicity with performance.
var colSums =
from col in array.Pivot()
select col.Sum();
public static class LinqExtensions {
public static IEnumerable<IEnumerable<T>> Pivot<T>( this IList<T[]> array ) {
for( int c = 0; c < array[ 0 ].Length; c++ )
yield return PivotColumn( array, c );
}
private static IEnumerable<T> PivotColumn<T>( IList<T[]> array, int c ) {
for( int r = 0; r < array.Count; r++ )
yield return array[ r ][ c ];
}
}
I would do it as follows … but this solution might actually be very slow so you might want to run a benchmark before deploying it in performance-critical sections.
var result = xs.Aggregate(
(a, b) => Enumerable.Range(0, a.Length).Select(i => a[i] + b[i]).ToArray()
);
It can be done with Zip and Aggregate. The question is so old that probably Zip was not around at the time. Anyway, here is my version, hoping it will help someone.
List<int[]> myListOfIntArrays = PopulateListOfArraysOf100Ints();
int[] totals = new int[100];
int[] allArraysSum = myListOfIntArrays.Aggregate(
totals,
(arrCumul, arrItem) => arrCumul.Zip(arrItem, (a, b) => a + b))
.ToArray();

Categories

Resources