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
Related
I hope someone has a good was of solving this problem.
So I have a list of doubles these being coordinates, example -123123, 12313. shown in image below.
List of doubles
these are being used in this foreach loop:
foreach (var coord in element.geometry.coordinates)
{
}
I'm trying to make a list of said coordinates - but instead of them being a list of single coordinates I need them to be compressed into two.
So rather than a list of
-1213123
1345
-345
1234535
I need a list of strings like so.
-1213123, 1345
-345, 1234535
using var 'coord' this being a single coordinate when coming out of the foreach loop. how can I create a list pairing every two values that come out of the loop.
Thanks for any help given :)
if the foreach loop is compulsory, then
string[] lst = new string[element.geometry.coordinates.Count() / 2];
int i=0;
foreach (var coord in element.geometry.coordinates)
{
if (i % 2 == 1)
lst[i-1] = $"{lst[i-1]}, coord";
else
lst[i] = coord
++i;
}
I know it looks a little bit weird, but you can you Linq.Zip method.
var coordinates = element.geometry.coordinates;
var result = coordinates
.Where((_, index) => index % 2 == 0) // Get even numbers
.Zip(
coordinates.Where((_, index) => index % 2 == 1), // Get odd numbers
(first, second) => $"{first}, {second}") // Zip them together
.ToList(); // If you need the result as List<string>
You cannot take a step other than 1 in a foreach loop. Therefore I propose to use a for loop instead. It can be set to step 2.
var doubles = new List<double> { -1213123, 1345, -345, 1234535 };
var strings = new List<string>();
for (int i = 0; i < doubles.Count; i += 2)
{
strings.Add(doubles[i] + ", " + doubles[i + 1]);
}
Do not need extra conditional if statements. This solution turns out to be as simple and effective as possible.
I'm trying to randomly get a specific integer (1) from a 2D array list filled with 0's and not many 1's. I made this, and it works:
while (wallsList[randomX, randomY] != 1)
{
randomX = randomizer.Next(34);
randomY = randomizer.Next(34);
}
The downside of it, it's that it takes too much time to just find one time the int (1), and I have to do this process over 1000 times since new 1's get added and removed to the 2D array each time. It takes about 3m to launch my program so I would like to know if there is an optimized version of this, I searched a lot and only found this solution for 1D arrays. Thanks for your time.
You have a sparse array. Why not represent it as a list of X/Y int pairs? Then, if the X/Y int pair is in the list, it's a 1, if not, it's a 0.
Then, to find a random value/cell containing 1, you just pick a random value from the list.
You could use a list like
new List <Tuple<int, int>> { new Tuple<int, int>(1, 5), new Tuple<int, int>(2, 7) }
Since most of your random guesses will fail, it would be far more efficient to build a second array of known good indexes and randomly search only those.
var randomizer = new Random();
var wallsList = new int[34, 34];
wallsList[23,11] = 1;
// Build an array of points that are known to pass
var knownHits =
(from x in Enumerable.Range(0, 34)
from y in Enumerable.Range(0, 34)
where wallsList[x, y] == 1
select new { x, y })
.ToArray();
// Pick a random point from previous array
var randomPoint = knownHits[randomizer.Next(knownHits.Length)];
var randomX = randomPoint.x;
var randomY = randomPoint.y;
Console.Write($"X = {randomX}, Y = {randomY}"); // X = 23, Y = 11
Alternatively, you could build the secondary array like this:
var knownHits = wallsList.Cast<int>()
.Select((v, i) => new { v, x = i / 34, y = i % 34 })
.Where(x => x.v == 1)
.ToArray();
There are a few approaches you can take. One would be to change your representation from a 2d array into something like a list of pairs of coordinates. Now selecting one at random is easy, but maybe some other operations you want to perform become harder. This approach and yours have the advantage that it selects one of the 1's uniformly. Another approach that would sacrifice this quality would be to choose a random x and y and then return the next 1, scanning by x or y. This is also not as efficient as the first solution.
I'm trying to randomly get a specific integer (1) from a 2D array list filled with 0's and not many
If you must do it randomly, your approach is fine. However, what you can improve it by avoiding drawing the same index again :
var randomizer = new Random();
var wallsList = new int[34, 34];
wallsList[01, 23] = 1;
var indexes =
from x in Enumerable.Range(0, 34)
from y in Enumerable.Range(0, 34)
select new { X = x, Y = y };
var result = indexes
.OrderBy(_ => randomizer.Next())
.FirstOrDefault(index => wallsList[index.X, index.Y] == 1);
if (result == null)
throw new Exception("Index not found");
Console.WriteLine("1 is found at[{0}, {1}]", result.X, result.Y);
Here's my problem. I have one specific list, which I'll present as a int[] for simplicity's sake.
int[] a = {1,2,3,4,5};
Suppose I need to transform each item on this list, but depending on the situation, I may return an int or an array of ints.
As an example, suppose I need to return {v} if the value is odd, and {v,v+1} if the value is even. I've done this:
int[] b = a.SelectMany(v => v % 2 == 0 ? new int[] { v, v+1 } : new int[] { v })
.ToArray();
So if I run this, I'll get the expected response:
{1,2,3,3,4,5,5}
See that I have repeating numbers, right? 3 and 5. I don't want those repeating numbers. Now, you may tell me that I can just call .Distinct() after processing the array.
This is the problem. The SelectMany clause is fairly complex (I just made up a simpler example), and I definitely don't want to process 3 if it's already present in the list.
I could check if 3 is present in the original list. But if I got 3 in the SelectMany clause, I don't want to get it again. For instance, if I had this list:
int[] a = {1,2,3,4,5,2};
I would get this:
{1,2,3,3,4,5,5,2,3}
Thus returning v (my original value) and v+1 again at the end. Just so you can understand it better v+1 represents some processing I want to avoid.
Summarizing, this is what I want:
I have a list of objects. (Check)
I need to filter them, and depending on the result, I may need to return more than one object. (Check, used SelectMany)
I need them to be distinct, but I can't do that at the end of the process. I should be able to return just {v} if {v+1} already exists. (Clueless...)
One thing I thought about is writing a custom SelectMany which may suit my needs, but I want to be sure there's no built-in way to do this.
EDIT: I believe I may have mislead you guys with my example. I know how to figure out if v+1 is in a list. To be clear, I have one object which has 2 int properties, Id and IdParent. I need to "yield return" all the objects and their parents. But I just have the ParentId, which comes from the objects themselves. I'm able to know if v+1 is in the list because I can check if any object there has the same Id as the ParentId I'm checking.
ANSWER: I ended up using Aggregate, which can be used to do exactly what I'm looking for.
Does this simple loop with the HashSet<int> help?
int[] a = {1,2,3,4,5,2};
var aLookupList = new HashSet<int>();
foreach (int i in a)
{
bool isEven = i % 2 == 0;
if (isEven)
{
aLookupList.Add(i);
aLookupList.Add(i + 1);
}
else
{
aLookupList.Add(i);
}
}
var result = aLookupList.ToArray();
What about this using Aggregate method. You won't be processing numbers that are already in the list, wheather they were in the original list or as a result of applying (v + 1)
int[] v = { 1, 2, 3, 4, 5, 2 };
var result = v.Aggregate(new List<int>(),
(acc, next) =>
{
if (!acc.Contains(next))
return (next % 2 == 0) ? acc.Concat(new int[] { next, next + 1 }).ToList()
: acc.Concat(new int[] { next }).ToList();
else
return acc;
}).ToArray();
var existing = new HashSet<int>(a);
var result = existing
.Where(v => v % 2 == 0 && !existing.Contains(v + 1))
.Select(v => v + 1)
.Concat(existing)
.ToArray();
As I understand you have this input:
int[] a = {1,2,3,4,5};
And the output should also be {1,2,3,4,5} because you don't want duplicated numbers as you describe.
Because you use an array as input, you can try this code:
var output = a.SelectMany((x,i)=> x % 2 == 0 ? new []{x,x+1} :
i > 0 && a[i-1]==x-1 ? new int[]{} : new []{x});
//if the input is {1,2,4,5}
//The output is also {1,2,3,4,5}
I am trying to return a number that represents the similarity between two arrays.
I.e :
Array1: {Katy, Jenny, Sarah, Ben, Jill, Tina}
Array2: {Katy, John, Sam, Ben, Jill, Linda}
I want to return the number 3 because three comparisons are correct. Is this
possible? I can't think of any functions that will do this for me.
This is how you can count the amount of items that are equal in matching indices.
var c = arr1.Where((x, i) => x.Equals(arr2[i])).Count();
Note that you might want to assure that you don't try to access arr2 in an index that is out of range:
var c = arr1.Take(arr2.Length).Count(...);
If you don't care about index positions, you should use nemesv's solution.
There are many ways to do this. Since others have already specified a few ways, I will try to post a different way of doing the same.
If you consider matching based on index, you can do something like this using Zip
var cnt = 0;
Array1.Zip(Array2,(a,b)=>{
if(a.Equals(b)) ++cnt;
return string.Empty; //we dont need this
}).Count(); // use tolist or count to force evaluation
If you don't care about ordering and are just concerned about matching, you can use Intersect
Array1.Intersect(Array2).Count()
The way I would approach this problem is too take the value in the first array and compare it with every other value in the second array. If they match than increase a compare counter and that will tell you their are three comparisons that match.
This works for me:
var array1 = new string[] {"Katy", "Jenny", "Sarah", "Ben", "Jill", "Tina"};
var array2 = new string[] {"Katy", "John", "Sam", "Ben", "Jill", "Linda"};
var similarity = (array1.Length + array2.Length) - array1.Union(array2).Count();
Edit: Oh just saw you want them to be in the same position.
You're saying "According to index", assuming you mean that if "John" is on position 1 in the first list, and on position 2 on the second list => no match.
In that case:
int maxItems = Math.Min(arr1.Length, arr2.Length);
int matchCount = 0;
for(int i = 0; i < maxItems; i++)
{
if(object.Equals(arr1[i], arr2[i]))
matchCount++;
}
I'd do it like this:
int count = array1.Zip(array2, (a, b) => a.Equals(b)).Count(b => b);
The zip part returns an IEnumerable<bool> and the count part count how many times true occurs in that list.
My code has a list called INPUTS, that contains a dynamic number of lists, let's call them A, B, C, .. N. These lists contain a dynamic number of Events
I would like to call a function with each combination of Events. To illustrate with an example:
INPUTS: A(0,1,2), B(0,1), C(0,1,2,3)
I need to call my function this many times for each combination (the input count is dynamic, in this example it is three parameter, but it can be more or less)
function(A[0],B[0],C[0])
function(A[0],B[1],C[0])
function(A[0],B[0],C[1])
function(A[0],B[1],C[1])
function(A[0],B[0],C[2])
function(A[0],B[1],C[2])
function(A[0],B[0],C[3])
function(A[0],B[1],C[3])
function(A[1],B[0],C[0])
function(A[1],B[1],C[0])
function(A[1],B[0],C[1])
function(A[1],B[1],C[1])
function(A[1],B[0],C[2])
function(A[1],B[1],C[2])
function(A[1],B[0],C[3])
function(A[1],B[1],C[3])
function(A[2],B[0],C[0])
function(A[2],B[1],C[0])
function(A[2],B[0],C[1])
function(A[2],B[1],C[1])
function(A[2],B[0],C[2])
function(A[2],B[1],C[2])
function(A[2],B[0],C[3])
function(A[2],B[1],C[3])
This is what I have thought of so far:
My approach so far is to build a list of combinations. The element combination is itself a list of "index" to the input arrays A, B and C. For our example:
my list iCOMBINATIONS contains the following iCOMBO lists
(0,0,0)
(0,1,0)
(0,0,1)
(0,1,1)
(0,0,2)
(0,1,2)
(0,0,3)
(0,1,3)
(1,0,0)
(1,1,0)
(1,0,1)
(1,1,1)
(1,0,2)
(1,1,2)
(1,0,3)
(1,1,3)
(2,0,0)
(2,1,0)
(2,0,1)
(2,1,1)
(2,0,2)
(2,1,2)
(2,0,3)
(2,1,3)
Then I would do this:
foreach( iCOMBO in iCOMBINATIONS)
{
foreach ( P in INPUTS )
{
COMBO.Clear()
foreach ( i in iCOMBO )
{
COMBO.Add( P[ iCOMBO[i] ] )
}
function( COMBO ) --- (instead of passing the events separately)
}
}
But I need to find a way to build the list iCOMBINATIONS for any given number of INPUTS and their events. Any ideas?
Is there actually a better algorithm than this?
any pseudo code to help me with will be great.
C# (or VB)
Thank You
You can use an array to hold the indexes for each list. Example:
List<List<int>> lists = new List<List<int>> {
new List<int> { 0,1,2 },
new List<int> { 0,1 },
new List<int> { 0,1,2,3 }
};
int[] cnt = new int[lists.Count];
int index;
do {
Console.WriteLine(String.Join(",", cnt.Select((c,i) => lists[i][c].ToString()).ToArray()));
index = cnt.Length - 1;
do {
cnt[index] = (cnt[index] + 1) % lists[index].Count;
} while(cnt[index--] == 0 && index != -1);
} while (index != -1 || cnt[0] != 0);
This is permutation problem. You may take a look at this:
http://www.interact-sw.co.uk/iangblog/2004/09/16/permuterate
I had similar problem some time ago (generating combinations), I've used code from: http://www.merriampark.com/comb.htm . It's java, but I hadn't any problems to translate it into C#.
Put A,B,C in matrix!
M=[A,B,C]
recursive_caller(d,params):
if d == len(M):
function(params)
return
for i in M[d]:
params[d]=i
recursive_caller(d+1,params)
It would seem that what you really want, is neither a permutation, nor a combination, per se. You want to look at the cartesian product (see here) of several sets, the iteration over which may involve iterating through combinations of individual sets.
However, this is unlike a combination problem, because you are looking for the ways to choose 1 element from each set. The number of ways to do this is the size of the set. Combinations problems usually involve choose k-many things from a set of n-many things, where k=1 or n is trivial.
Several methods of producing iterators in C# have been discussed here. (Including one by Jon Skeet).
If you are using .NET, you may also be interested in developed combinatorics modules, such as KwCombinatorics at CodePlex.
edit Now, with LINQ to the rescue:
private void cartesian1()
{
textAppend("Cartesian 1");
var setA = new[] { "whole wheat", "white", "rye" };
var setB = new[] { "cold cut", "veggie", "turkey", "roast beef" };
var setC = new[] { "everything", "just mayo" };
var query =
from bread in setA
from meat in setB
from toppings in setC
let sandwich = String.Format("{1} on {0} with {2}",
bread, meat, toppings)
select sandwich;
foreach( string sandwich in query )
{
textAppend(sandwich);
}
}
A modified version of #Guffa's answer. I am by no means a creator of this code.
List<int> lists = new List<int> { 3, 2, 4 };
int[] cnt = new int[lists.Count];
int index;
do
{
Console.WriteLine(String.Join(",", cnt));
index = cnt.Length - 1;
do
{
cnt[index] = (cnt[index] + 1) % lists[index];
} while (cnt[index--] == 0 && index != -1);
} while (index != -1 || cnt[0] != 0);
Instead of using List<List<int>> - with possible values - use List<int> describing the amount of elements in collection. The output is the same an in original answer. The performance is better.