Advanced Remove Array Duplicated - c#

I have 3 arrays.
Array 1 = {1,1,1,1,2,2,3,3}
Array 2 = {a,a,a,a,e,e,b,b}
Array 3 = {z,z,z,z,z,z,z,z}
I would like to remove all duplicates from array 1 and also remove the same element at said duplicate in the other arrays to keep them all properly linked.
I know you can use .Distinct().ToArray() to do this for one array, but then the other arrays would not have the elements removed as well.
The result would look like this.
Array 1 = {1,2,3}
Array 2 = {a,e,b}
Array 3 = {z,z,z}
I'm guessing the only way to solve this would be the following.
For(int a = 0; a < Array1.count; a++) {
For(int b = a + 1; b < Array1.count; b++) {
if(Array1[a]==Array1[b]) {
Array1.RemoveAt(b);
Array2.RemoveAt(b);
Array3.RemoveAt(b);
}
}
}
Would be nice to find a simple predefined function however!

var distinctIndexes = array1
.Select((item, idx) => new { Item = item, Index = idx })
.GroupBy(p => p.Item)
.Select(grp => grp.First().Index);
var result1 = distinctIndexes.Select(i => array1[i]).ToArray();
var result2 = distinctIndexes.Select(i => array2[i]).ToArray();
var result3 = distinctIndexes.Select(i => array3[i]).ToArray();
Note this won't necessarily use the first unique element from the first array. If you need to do that you can calculate the indexes as
var distinctIndexes = array1
.Select((item, idx) => new { Item = item, Index = idx })
.Aggregate(new Dictionary<int, int>(), (dict, i) =>
{
if (! dict.ContainsKey(i.Item))
{
dict[i.Item] = i.Index;
}
return dict;
})
.Values;

You should consider what data structure you're using carefully. Is this "remove" operation likely to happen all at once? How often? (I'm not challenging your use of Array necessarily, just a general tip, but your scenario seems weird). Also, you did not explain if this is an index-based removal or an element based removal. If I was implementing this, I would be tempted to create a new Array and add all remaining elements to the new Array in a loop, ignoring the elements you want to remove. Then simply reassign the reference with '='. Of course, that depends on the maximum expected size of the Array, since a copy like I suggested would take up more memory (usually wouldn't be a problem).

I don't really know of a clean way to do what you're asking, but this is a generic example of doing what you asked?
static void RemoveDupes(ref Array a1, ref Array a2, ref Array a3)
{
Type a1t, a2t, a3t;
int newLength, ni, oi;
int[] indices;
a1t = a1.GetType().GetElementType();
a2t = a1.GetType().GetElementType();
a3t = a1.GetType().GetElementType();
Dictionary<object, List<int>> buckets = new Dictionary<object, List<int>>();
for (int i = 0; i < a1.Length; i++)
{
object val = a1.GetValue(i);
if (buckets.ContainsKey(val))
buckets[val].Add(i);
else
buckets.Add(val, new List<int> { i });
}
indices = buckets.Where(kvp => kvp.Value.Count > 1).SelectMany(kvp => kvp.Value.Skip(1)).OrderBy(i => i).ToArray();
newLength = a1.Length - indices.Length;
Array na1 = Array.CreateInstance(a1t, newLength);
Array na2 = Array.CreateInstance(a2t, newLength);
Array na3 = Array.CreateInstance(a3t, newLength);
oi = 0;
ni = 0;
for (int i = 0; i < indices.Length; i++)
{
while (oi < indices[i])
{
na1.SetValue(a1.GetValue(oi), ni);
na2.SetValue(a2.GetValue(oi), ni);
na3.SetValue(a3.GetValue(oi), ni);
oi++;
ni++;
}
oi++;
}
while (ni < newLength)
{
na1.SetValue(a1.GetValue(oi), ni);
na2.SetValue(a2.GetValue(oi), ni);
na3.SetValue(a3.GetValue(oi), ni);
oi++;
ni++;
}
a1 = na1;
a2 = na2;
a3 = na3;
}

Related

C# LINQ - SkipWhile() in reverse, without calling Reverse()?

In this code:
for (e = 0; e <= collection.Count - 2; e++)
{
var itm = collection.Read()
var itm_price = itm.Price
var forwards_satisfied_row = collection
.Skip(e + 1)
.SkipWhile(x => x.Price < ex_price)
.FirstOrDefault();
var backwards_satisfied_row = collection
.Reverse()
.Skip(collection.Count - e)
.SkipWhile(x => x.Price < ex_price)
.FirstOrDefault();
}
Suppose the collection contains millions of items and a Reverse() is too expensive, what would be the best way to achieve the same outcome as 'backwards_satisfied_row' ?
Edit:
For each item in the collection, it should find the first preceding item that matches the SkipWhile predicate.
For context I'm finding the distance a price extrema (minima or maxima) is from a horizontal clash with the price. This gives a 'strength' value for each Minima and Maxima, which determines the importance of it, and to help marry it up with extremas of a similar strength.
Edit 2
This chart shows the data in the reproc code below, note the dip in the middle at item #22, this item has a distance of 18.
Bear in mind this operation will be iterated millions of times.
So I'm trying not to read into memory, and to only evaluate the items needed.
When I run this on a large dataset r_ex takes 5 ms per row, whereas l_ex takes up to a second.
It might be tempting to iterate backwards and check that way, but there could be millions of previous records, being read from a binary file.
Many types of searches like Binary search wouldn't be practical here, since the values aren't ordered.
static void Main(string[] args)
{
var dict_dists = new Dictionary<Int32, Int32>();
var dict = new Dictionary<Int32, decimal> {
{1, 410},{2, 474},{3, 431},
{4, 503},{5, 461},{6, 535},
{7, 488},{8, 562},{9, 508},
{10, 582},{11, 522},{12, 593},
{13, 529},{14, 597},{15, 529},
{16, 593},{17, 522},{18, 582},
{19, 510},{20, 565},{21, 492},
{22, 544},{23, 483},{24, 557},
{25, 506},{26, 580},{27, 524},
{28, 598},{29, 537},{30, 609},
{31, 543},{32, 612},{33, 542},
{34, 607},{35, 534},{36, 594},
{37, 518},{38, 572},{39, 496},
{40, 544},{41, 469},{42, 511},
{43, 437},{44, 474},{45, 404},
{46, 462},{47, 427},{48, 485},
{49, 441},{50, 507}};
var i = 0;
for (i = 0; i <= dict.Count - 2; i++)
{
var ele = dict.ElementAt(i);
var current_time = ele.Key;
var current_price = ele.Value;
var is_maxima = current_price > dict.ElementAt(i + 1).Value;
//' If ele.Key = 23 Then here = True
var shortest_dist = Int32.MaxValue;
var l_ex = new KeyValuePair<int, decimal>();
var r_ex = new KeyValuePair<int, decimal>();
if (is_maxima)
{
l_ex = dict.Reverse().Skip(dict.Count - 1 - i + 1).SkipWhile(x => x.Value < current_price).FirstOrDefault();
r_ex = dict.Skip(i + 1).SkipWhile(x => x.Value < current_price).FirstOrDefault();
}
else
{ // 'Is Minima
l_ex = dict.Reverse().Skip(dict.Count - 1 - i + 1).SkipWhile(x => x.Value > current_price).FirstOrDefault();
r_ex = dict.Skip(i + 1).SkipWhile(x => x.Value > current_price).FirstOrDefault();
}
if (l_ex.Key > 0)
{
var l_dist = (current_time - l_ex.Key);
if ( l_dist < shortest_dist ) {
shortest_dist = l_dist;
};
}
if (r_ex.Key > 0)
{
var r_dist = (r_ex.Key - current_time);
if ( r_dist < shortest_dist ) {
shortest_dist = r_dist;
};
}
dict_dists.Add(current_time, shortest_dist);
}
var dist = dict_dists[23];
}
Edit: As a workaround I'm writing a reversed temp file for the left-seekers.
for (i = file.count - 1; i >= 0; i += -1)
{
file.SetPointerToItem(i);
temp_file.Write(file.Read());
}
You could make it more efficient by selecting the precedent of each item in one pass. Lets make an extension method for enumerables that selects a precedent for each element:
public static IEnumerable<T> SelectPrecedent<T>(this IEnumerable<T> source,
Func<T, bool> selector)
{
T selectedPrecedent = default;
foreach (var item in source)
{
if (selector(item)) selectedPrecedent = item;
yield return selectedPrecedent;
}
}
You could then use this method, and select the precedent and the subsequent of each element by doing only two Reverse operations in total:
var precedentArray = collection.SelectPrecedent(x => x.Price < ex_price).ToArray();
var subsequentArray = collection.Reverse()
.SelectPrecedent(x => x.Price < ex_price).Reverse().ToArray();
for (int i = 0; i < collection.Count; i++)
{
var current = collection[i];
var precedent = precedentArray[i];
var subsequent = subsequentArray[i];
// Do something with the current, precedent and subsequent
}
No need to do .Reverse() and then FirstOrDefault(), just use LastOrDefault(). Instead of Skip(collection.Count - e) use .Take(e) elements
var backwards_satisfied_row = collection
.SkipWhile(x => x.Price < ex_price) //Skip till x.Price < ex_price
.Skip(e+1) //Skip first e+1 elements
.LastOrDefault(); //Get Last or default value
You can make your code more efficient by storing collection and then just get FirstOrDefault() and LastOrDefault() for forwards_satisfied_row and backwards_satisfied_row respectively.
like,
for (e = 0; e <= collection.Count - 2; e++)
{
var itm = collection.Read()
var itm_price = itm.Price
var satisfied_rows = collection
.SkipWhile(x => x.Price < ex_price)
.Skip(e + 1)
.ToList();
var forwards_satisfied_row = satisfied_rows.FirstOrDefault();
var backwards_satisfied_row = satisfied_rows.LastOrDefault();
}

Skip blank rows in 2D string array effectively [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Consider 2D array like this one:
With the following code the empty rows are skipped:
public static string[,] SkipBlankRows(this string[,] array2D)
{
var columns = array2D.GetLength(1);
var rows = array2D.GetLength(0);
var temp = new List<string[]>();
for (var r = 0; r < rows; r++)
{
var row = new string[columns];
for (var c = 0; c < columns; c++)
{
row[c] = array2D[r, c];
}
if (row.All(itm => string.IsNullOrWhiteSpace(itm)))
continue;
temp.Add(row);
}
string[,] result = new string[temp.Count(), columns];
rows = temp.Count();
for (int r = 0; r < rows; r++)
{
var row = temp[r];
for (var c = 0; c < row.Length; c++)
{
result[r,c]=row[c];
}
}
return result;
}
Usage:
void Main()
{
var x = new string[,] { { "", "", "" }, { "", "X", "" }, { "X", "X", "X" }, { "", "", "" }, {"X","","X"}, {"X","X","X"}};
var y = x.SkipBlankRows();
}
Result:
The result should be 2D-array of string where the blank rows will not be there.
The code looks awkward to me, is it possible to do it better e.g. to involve linq?
You could use LINQ to get the string[,] to an IEnumerable<IEnumerable<string>> with the empty rows removed, then put the IEnumerable<IEnumerable<string>> back into a string[,]. I'm not aware of any way with LINQ to project an IEnumerable<IEnumerable<string>> into a string[,], so I just used nested foreach loops.
public static string[,] SkipBlankRows(this string[,] array2D)
{
int columnCount = array2D.GetLength(1);
var withoutEmptyLines = array2D
.Cast<string>() // Flatten the 2D array to an IEnumerable<string>
.Select((str, idx) => new { str, idx }) // Select the string with its index
.GroupBy(obj => obj.idx / columnCount) // Group the items into groups of "columnCount" items
.Select(grp => grp.Select(obj => obj.str)) // Select the groups into an IEnumerable<IEnumerable<string>>
.Where(strs => !strs.All(str => string.IsNullOrWhiteSpace(str))); // Filter empty rows;
// Put the IEnumerable<IEnumerable<string>> into a string[,].
var result = new string[withoutEmptyLines.Count(), columnCount];
int rowIdx = 0;
foreach (var row in withoutEmptyLines)
{
int colIdx = 0;
foreach (var col in row)
{
result[rowIdx, colIdx++] = col;
}
rowIdx++;
}
return result;
}
LINQ was intended to process and produce collections rather than multidimensional arrays. You can replace the first for loop with some LINQ that's a little more expressive, but you can't really get away from using for loops for repopulating the new array:
public static string[,] SkipBlankRows(this string[,] array2D)
{
var columns = array2D.GetLength(1);
var rows = array2D.GetLength(0);
var temp = Enumerable.Range(0, rows)
.Select(i => Enumerable.Range(0, columns).Select(j => array2D[i, j]).ToList())
.Where(row => !row.All(string.IsNullOrEmpty))
.ToList();
string[,] result = new string[temp.Count, columns];
rows = temp.Count;
for (int r = 0; r < rows; r++)
{
var row = temp[r];
for (var c = 0; c < row.Count; c++)
{
result[r, c] = row[c];
}
}
return result;
}
Of course, if you're willing to bring in a couple of helper methods to abstract away the conversion to and from rows, you can end up with a highly efficient and very easy-to-read code.
How to get a complete row or column from 2D array in C#
Converting jagged array to 2D array C#
It depends on what you want your output to look like, do you just want to skip over the blank strings and have a list of values? Or do you want your data to still be in the multi-dimentional array?
If your answer to this question is "the second one" then your code is fine.
If you just want a list of all of the values out of the multi-dimentional array you could write something like:
public static IEnumerable<string> SkipBlankRows(this string[,] array2D)
{
return (from string s in array2D where !string.IsNullOrWhiteSpace(s) select s);
}
This returns a flat structure of values from the array.
Hope this helps

Randomize two List<string> in C# in same order

I have two string lists en and en1
List<string> en = new List<string>(new string[] { "horse", "cat", "dog", "milk", "honey"});
List<string> en1 = new List<string>(new string[] { "horse1", "cat2", "dog3", "milk4", "honey5" });
And I want radomize their content "Shuffle them" and put this radomized content to new two lists.
But I also want them randomize same way so lists after randomization will still be
en[0] == en1[0]
random content after randomization
{ "cat", "horse", "honey", "milk", "dog"}
{ "cat2", "horse1", "honey5", "milk4", "dog3"}
Two obvious ways:
Take a normal shuffle method, and change it to modify both lists at the same time
Transform the two lists into a single joint list, shuffle that, then split them again
The second sounds cleaner to me. You'd use something like:
var joined = en.Zip(en1, (x, y) => new { x, y }).ToList();
var shuffled = joined.Shuffle(); // Assume this exists
en = shuffled.Select(pair => pair.x).ToList();
en1 = shuffled.Select(pair => pair.y).ToList();
Third obvious way:
Shuffle a list of integers 0, 1, ... , Count-1 and use this list as indexes into the original lists.
Edit
This goes along this lines (for user38...):
List<int> shuffeledIndex = new List<int>();
for(int i = 0; i < en.Count; i++) shuffeledIndex.Add(i);
shuffeledIndex.Shuffle(); // Assume this exists
enshuffeled = en[shuffeledIndex[i]]; // instead en[i]
en1shuffeled = en1[shuffeledIndex[i]];
Adding to Jon Skeet's answer, a nice way to do the shuffling is OrderBy(x => Guid.NewGuid()) so the code would look like
var joined = en.Zip(en1, (x, y) => new { x, y });
var shuffled = joined.OrderBy(x => Guid.NewGuid()).ToList();
en = shuffled.Select(pair => pair.x).ToList();
en1 = shuffled.Select(pair => pair.y).ToList();
Well, I think #Jon Skeet's answer is better than mine (since I only know the basics about C# and probably for some other reasons... :P), however you could shuffle your lists manually with something like this:
for(int i=0;i<en.Count;i++) {
int remainingCount = en.Count - 1;
int exchangeIndex = i + (new Random()).nextInt(0, remainingCount);
swap(en, i, exchangeIndex);
swap(en1, i, exchangeIndex);
}
Of course you would need to write a swap function like swap(List<string> list, int indexA, int indexB):
string tmp = list[indexA];
list[indexA] = list[indexB];
list[indexB] = tmp;
You could first combine the two lists into one using the Zip function:
var zipped = en.Zip(en1, (first, second) => new { first, second }).ToList();
You'll then need a shuffling function to shuffle them. You could use the Fisher–Yates shuffle in an extension method:
public static void FisherYatesShuffle<T>(this IList<T> list)
{
var rnd = new Random();
var x = list.Count;
while (x > 1) {
x--;
var y = rnd.Next(x + 1);
T value = list[y];
list[y] = list[x];
list[x] = value;
}
}
To use the extension method:
var shuffled = zipped.FisherYatesShuffle();
Now you can split them back out again into two separate lists:
en = shuffled.Select(combined => combined.x).ToList();
en1 = shuffled.Select(combined => combined.y).ToList();

Find closest value in an array List with linq?

I've a list like this:
public static List<int[]> list = new List<int[]>();
In addition I have also a variable named X. X can take any value. I want to find closest and smaller value to X in list[?][1]. For example:
If X is 1300, I want to take list index: 1. Or if X is 700, I want to take index: 0. How can I do this via linq? Or, is there any other solution?
Thanks in advance.
You can do it in a following way (snippet assumes, that list is not empty)
var x = 700;
var result = list.Select((subList, idx) => new { Value = subList[1], Idx = idx })
.Where(elem => elem.Value < x)
.Select(elem => new { Diff = Math.Abs(x - elem.Value), elem.Idx })
.OrderBy(elem => elem.Diff).FirstOrDefault();
if (result != null)
{
return result.Idx;
}
// case - there is no such index
I know you asked for a Linq solution, but I think that a non-Linq solution is also good.
If you are interested in a non-Linq solution, here's one (it does use Linq in one place, but really that's stretching the point!).
The main method of interest, FindClosestSmaller(), returns a Tuple where .Item1 is the index of the outer list that contains the closest value that is less than or equal to a target value, and .Item2 is the index of that match in the inner array.
If no value less than or equal to the target value is found, .Item1 and .Item2 will both be zero.
Note that FindClosestSmaller() takes a parameter of type IEnumerable<IEnumerable<int>>, which means you can use it with most collection types and you aren't just limited to, say, List<int[]>.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public static class Program
{
private static void Main()
{
var ints1 = new [] { 1, 480, 749, 270 };
var ints2 = new [] { 1, 810, 1080, 271 };
var ints3 = new [] { 1, 7680, 7949, 271 };
var intLists = new List<int[]> {ints1, ints2, ints3};
test(intLists, 1300);
test(intLists, 700);
test(intLists, 480);
test(intLists, 0);
}
private static void test(List<int[]> values, int target)
{
var result = FindClosestSmaller(values, target);
Console.WriteLine("Target {0} found: Outer index = {1}, Inner index = {2}", target, result.Item1, result.Item2);
}
public static Tuple<int, int> FindClosestSmaller(IEnumerable<IEnumerable<int>> sequences, int target)
{
int closest = int.MaxValue;
int closestInner = 0; // Setting these to zero means we take the first element of the
int closestOuter = 0; // first list if no smaller element is found.
int outer = 0;
foreach (var sequence in sequences)
{
int inner = 0;
foreach (int distance in sequence.Select(value => target - value))
{
if ((distance >= 0) && (distance < closest))
{
closest = distance;
closestInner = inner;
closestOuter = outer;
}
++inner;
}
++outer;
}
return new Tuple<int, int>(closestOuter, closestInner);
}
}
}
You can start by flatten elements to a new anonymous type where index is the index in the outer array, and item is the value in the inner array:
Assume input and a desired target value:
var target = 20;
var input = (new int[][]{new int[]{1,2,3}, new int[]{4,7,8}, new int[]{5,4}});
Then flattening would be
var tmp = input.SelectMany((x, y) => x.Select(item =>
new {index = y, item = item, delta = Math.Abs(target - item)}));
Now you can find the optimal delta:
var bestDelta = tmp.Min(x => x.delta);
And from this it is simple to find the best match:
var result = tmp.FirstOrDefault(x => x.delta == bestDelta);
Or if you prefer simply to get the index:
var index = tmp.Where(x => x.delta == bestDelta).Select(x => x.index).First();
This could be rewritten to the oneliner:
var result = input.SelectMany((x, y) =>
x.Select(item => new {index = y, item = item, delta = Math.Abs(target - item)}))
.OrderBy(x => x.delta).Select(x => x.index).First();
But I tend to find the other solution more readable.

Looping through x number of arrays

How do I loop through x number of arrays and visit all combinations of all cells in all of the arrays? The problem here is there can be x number of arrays of some items inside. For instance,
List<List<string>> _arrays = GetArrayInformation();
I want to compare all the string inside each array with all the other arrays and the strings inside of each array. Do I use while like
while(i < _arrays.Count)
Thanks for your answer. The answer seems simple but when you think about it is kind of tricky and hard.
Update:
Thanks for your answers. I can do this with a 3 arrays like
for(int i = 0; i < _arrays[0].Count; i++) {
for(int l = 0; l < _arrays[1].Count; l++) {
for(int m = 0; m < _arrays[2].Count; m++) {
string _hello = _arrays[0][i] + "|" + _arrays[1][l] + "|" + _arrays[2][m];
}
}
}
Because I have dynamic number of arrays, it gets tricky.
foreach(var array in _arrays)
{
foreach(var s in array)
{
foreach(var otherArray in _arrays)
{
if(otherArray == array) continue;
if(otherArray.Contains(s)) {} // not sure what you want to do
}
}
}
this will loop through every single string seeing if it is in any other array.... it's the straightforward approach, but not very efficient and will duplicate work.
There is no enough information is here
If you need to find elements that exists in few array You will use something like this:
var multipleWords = _arrays
.SelectMany(items => items.Distinct())
.GroupBy(item => item)
.Select(group => new {Item = group.Key, Count = group.Count()})
.Where(item => item.Count > 1)
.Select(item => item.Item)
.ToArray();
multipleWords will contain each word from the all these arrays that exists in two or more arrays
You could use a recursive search function.
public Search<T>(object o, string comparestring)
{
if(o is List<string>)
{
//Compare to your string
}
else
{
//Call this search function with the type of the object in the list.
//Will iterate through all of your strings recursively.
Type t = o.GetType().GetGenericArguments()[0];
foreach( object osub in (T)o)
Search<t>( ((t)o),comparestring)
}
}

Categories