Jagged Array[][] find all selected elements in column - c#

I have a jagged array:
int[][] loadData
a1
o1 | 3 1 5 4 3 3 1
o2 | 1 4 1 2 2 1 0
o3 | 4 4 5 4 4 3 1
o4 | 2 3 4 4 5 4 1
o5 | 3 3 5 2 5 5 1
o6 | 3 3 3 1 5 2 0
o7 | 2 5 3 5 1 2 1
o8 | 4 5 4 4 4 1 0 // this is my jagged array without o1 and a1 I use them for example
I want find all elements in column a1 who have number 3. I tried to mix the code but with no effect.
for example for 3 in column a1:
Dictionary<int, int?>[] matrix = new Dictionary<int, int?>[8];
matrix[0].Add(1, 3);
matrix[0].Add(5, 3);
matrix[0].Add(6, 3);
var x = Array.FindAll(loadData, a => Enumerable.Range(0, s)
.Select(j => loadData[j][0]));`
How to solve it?

The answer depends on what you mean by "find all."
If you want to find and count the number of rows, you can just
var count = array.Count( a => a[0] == 3 );
If you want to output the row numbers, it's a little trickier, since you have to pass the row number through before you apply the Where portion, or else the original row number will be lost.
var indexes = array.Select
(
(a, i) =>
new { RowNumber = i, Value = a[0]}
)
.Where( n => n.Value == 3 )
.Select( r => r.RowNumber )
You could also just flatten the array:
var flatList = array.SelectMany
(
(array, row) =>
array.Select
(
(element,column) =>
new { Row = row, Column = column, Value = element }
)
);
...and then query it like a flat table:
var indexes = flatList.Select
(
element => element.Column = 0 && element.Value == 3
)
.Select( a => a.Row );

I could be wrong but I think you may be looking for using linq is utilizing a .Where clause on a SelectMany statement. I had a question posted that was kind of similar although i was converting it into a string[][] array. https://stackoverflow.com/a/47784942/7813290

Related

Get index array of value changes or first distinct values from array of Objects

I have a sorted array of objects that contains 3 doubles, lets call them x, y and z. I need to create an array of indexes for each transition point, example:
index x y z
------------------
0 | 3 | 2 | 1
1 | 4 | 3 | 1
2 | 3 | 1 | 1
3 | 1 | 3 | 2
4 | 3 | 1 | 2
5 | 1 | 3 | 3
6 | 1 | 3 | 3
Should give me the array {3,5} as that is the point where z changes, I have tried
var ans = myObjectArr.Select(a => a.z).Distinct().ToList();but that simply gives me a list of the values themselves and not the index they are in the object array. The array is very large and i would like to avoid iterating my way through it discreetly. I feel like i'm just missing something silly and any help would be appreciated. Generating a list or an array would both be acceptable.
EDIT: I was under the impression that using Linq was faster than doing it iteratively, after reading comments i find this not to be the case and because of this Charlieface's answer is the best one for my problem.
var lastZ = myObjectArr[0].z;
var zIndexes = new List<int>();
for(var i = 1; i < myObjectArr.Length; i++)
{
if(myObjectArr[i] != lastZ)
{
lastZ = myObjectArr[i];
zIndexes.Add(i);
}
}
// or you can use obscure Linq code if it makes you feel better
var zIndexes = myObjectArr
.Select((o, i) => (o, i))
.Skip(1)
.Aggregate(
new List<int>(),
(list, tuple) => {
if(tuple.o.z != lastZ)
{
lastZ = tuple.o.z;
list.Add(tuple.i);
}
return list;
} );

Find Top X most similar users, based on Y boolean attributes

Let's say I have 5 users, each with 5 boolean attributes, which could look like this:
| A B C D E
--------------------------
User 0 | 1 1 0 1 0
User 1 | 0 1 0 1 0
User 2 | 0 0 1 0 1
User 3 | 1 1 0 0 0
User 4 | 0 0 0 1 0
Now what would be the best approach to get a list of the top x users with the most "trues" in common. So in the example above the ranking should look like his:
Top 1: Users 0 (most true attributes)
Top 2: Users 0 and 1 OR Users 0 and 3 (both pairs have 2 attributes in common)
Top 3: Users 0, 1 and 3
Top 4: Users 0, 1, 3 and 4
Top 5: Users 0, 1, 2, 3, 4
I know there are metrics and distance measures to tell how similar two users are, but i want a list of most similar ones. Should i use some kind of clustering algorithm? But which one would consider multiple binary attributes and how could I implement it (preferably in C#)?
Since I haven't taken any classes on data mining, the literature on this topic is kinda overwhelming, so any help is highly appreciated.
User mostTrueUser = Users
.OrderByDescending(u => (u.A?1:0) + (u.B?1:0) + (u.C?1:0) + (u.D?1:0) + (u.E?1:0))
.First();
var groups = Users.GroupBy(u => ((u.A && mostTrueUser.A)?1:0)
+((u.B && mostTrueUser.B)?1:0)
+((u.C && mostTrueUser.C)?1:0)
+((u.D && mostTrueUser.D)?1:0)
+((u.E && mostTrueUser.E)?1:0)
,u => u).OrderByDescending(g => g.Key);
foreach(var group in groups)
{
Console.WriteLine("{0} // following have {0} 'true' in common with {1}",
group.Key,
mostTrueUser.ID);
foreach(var g in group)
{
Console.WriteLine(" " + g.ID);
}
}
This gives me the following:
3 // following have 3 'true' in common with 0
0
2 // following have 2 'true' in common with 0
1
3
1 // following have 1 'true' in common with 0
4
0 // following have 0 'true' in common with 0
2
Explanations
I used u.A?1:0 so true becomes 1 and false becomes 0.
I then got the User with most true using OrderByDescending([sum of trues]).
Then the GroupBy is used to group all Users on the number of true in common with the mostTrueUser.
Your ranking seems a little bit more complicated, but you can start with this to solve it.
I wrote a little tweak:
public class UserRank
{
public User UserA{get;set;}
public User UserB{get;set;}
public int Compare{
get{return ((UserA.A && UserB.A)?1:0)
+((UserA.B && UserB.B)?1:0)
+((UserA.C && UserB.C)?1:0)
+((UserA.D && UserB.D)?1:0)
+((UserA.E && UserB.E)?1:0);}
}
}
and then:
List<UserRank> userRanks = new List<UserRank>();
for(int i=0;i<Users.Count;i++)
{
for(int j=i;j<Users.Count;j++)
{
userRanks.Add(new UserRank
{
UserA = Users[i],
UserB = Users[j]
});
}
}
var groups = userRanks.GroupBy(u => u.Compare, u => u).OrderByDescending(g => g.Key);
foreach(var group in groups)
{
Console.WriteLine("{0} in common:",group.Key);
foreach(var u in group)
{
Console.WriteLine(" {0}-{1}",u.UserA.ID,u.UserB.ID);
}
}
gives me:
3 in common:
0-0
2 in common:
0-1
0-3
1-1
2-2
3-3
1 in common:
0-4
1-3
1-4
4-4
0 in common:
0-2
1-2
2-3
2-4
3-4
TutorialsPoint CodingGround permalink for testing purpose

How to Type it in LINQ?

i am learning C# and LINQ so i am sorry for that question.
how to type in linq to group the same elements in certain array, but when they group it they see if the count of the group is greater than 2 and then division it by 2 and return the value of the group count and then add it to int
what i want the linq to do in code :
s => s > 2
s /= 2
return s;
my original code is that:
int n = Convert.ToInt32(Console.ReadLine());
string[] userinput = Console.ReadLine().Split(' ');
int[] socks = new int[n];
socks = Array.ConvertAll(userinput, Int32.Parse);
var result = socks.GroupBy(s => s > 2).ToArray(); //This is the line which i want help
int total = 0;
foreach (var group in result)
{
total += group.Count();
Console.WriteLine(group.Count());
}
Lets assume we have 10 kinds of socks. which are 10,20,30,40,50,60,70, 80,90,100
now in the first line i enter the number of the socks i have so for example its 5.
in the second line i enter the 5 socks kinds for example. 10 10 20 20 30
now i want the linq code to define that there is 3 keys here which are 10 20 30, the 10 key has more than only 1 count it has 2. the same for 20 but the 30 only have 1 so lets forget about the 30. now the count of they key of each one of them is 2 so lets divide it by 2 for each one then add the divided number to the total so 2/2 for each one equals 1 so total = 2 (this is the my expected output)
If understand you right, you want to count pairs of socks:
int total = socks
.GroupBy(x => x)
.Sum(chunk => chunk.Count() / 2);
According to your example:
[10, 10, 20, 20, 30]
after grouping socks by their sizes
10: [10, 10] - 2 socks, 1 pair (you've put it as "divide by 2")
20: [20, 20] - 2 socks, 1 pair
30: [30] - 1 sock, 0 pairs
-------------------------------
2 pairs in total (the expected value)
My example (from the comments to the question)
1, 2, 2, 2, 3, 4, 5, 5
should return 2 as well (we have 2 pairs: of size 2 and 5)
In case you want to get pairs:
var pairs = socks
.GroupBy(x => x)
.Select(chunk => new {
size = chunk.Key,
count = chunk.Count() / 2, });
//.Where(pair => pair.count > 0); // you may want to filter out single socks

List Sorting for treeview via linq

I have A list
key ParentKey
1 Null
2 1
3 Null
4 Null
5 1
6 4
7 6
8 3
I want it sorted in
key ParentKey
1 Null
2 1
5 1
3 Null
8 3
4 Null
6 4
7 6
via linq how can this be done?
Any help is most wellcome
Assuming that the result should be:
key ParentKey
1 Null
2 1
5 1
3 Null
8 3
4 Null
6 4
7 6
I can say that you can't do anything if there isn't a logic that make the null values in that position into the list.
So using Linq you can order the list using the OrderBy() function:
list = list.OrderBy(x => x.ParentKey).ToList();
But using this function the result is the following:
key ParentKey
1 Null
3 Null
4 Null
2 1
5 1
8 3
6 4
7 6
if you have a list of
public class MyObject{
int Key {get;set;}
int ? ParentKey{get;set;}
}
then for sorting this list use :
var list = new List<MyObject>(){ new MyObject{ Key = 1 , ParentKey = null } , new MyObject{Key=2 , PatentKey = 1} /* and so on */};
var sortedList = list.OrderBy(o=>o.ParentKey , new MyComparer());
public class MyComparer : IComparer<MyObject>
{
public int Compare(MyObject o1, MyObject o2)
{
if (ol.HasValue && o2.HasValue)
{
if (ol.ParentKey.Value == o2.ParentKey.Value)
return 0;
return ol.ParentKey.Value > o2.ParentKey.Value ? 1 : -1;
}
else
return 0;
}
}
this will generate exact your expecting sequence
I believe what you want to achieve here is a DFS ordered print of a tree.
Linq can't help you with that (at least out of the box).
I'd suggest adapting a DFS implementation to your data structure. See Eric Lippert's suggestion.

Generate N random and unique numbers within a range

What is an efficient way of generating N unique numbers within a given range using C#? For example, generate 6 unique numbers between 1 and 50. A lazy way would be to simply use Random.Next() in a loop and store that number in an array/list, then repeat and check if it already exists or not etc.. Is there a better way to generate a group of random, but unique, numbers?
To add more context, I would like to select N random items from a collection, using their index.
thanks
Take an array of 50 elements: {1, 2, 3, .... 50}
Shuffle the array using any of the standard algorithms of randomly shuffling arrays. The first six elements of the modified array is what you are looking for. HTH
For 6-from-50, I'm not too sure I'd worry about efficiency since the chance of a duplicate is relatively low (30% overall, from my back-of-the-envelope calculations). You could quite easily just remember the previous numbers you'd generated and throw them away, something like (pseudo-code):
n[0] = rnd(50)
for each i in 1..5:
n[i] = n[0]
while n[1] == n[0]:
n[1] = rnd(50)
while n[2] == any of (n[0], n[1]):
n[2] = rnd(50)
while n[3] == any of (n[0], n[1], n[2]):
n[3] = rnd(50)
while n[4] == any of (n[0], n[1], n[2], n[3]):
n[4] = rnd(50)
while n[5] == any of (n[0], n[1], n[2], n[3], n[4]):
n[5] = rnd(50)
However, this will break down as you move from 6-from-50 to 48-from-50, or 6-from-6, since the duplicates start getting far more probable. That's because the pool of available numbers gets smaller and you end up throwing away more and more.
For a very efficient solution that gives you a subset of your values with zero possibility of duplicates (and no unnecessary up-front sorting), Fisher-Yates is the way to go.
dim n[50] // gives n[0] through n[9]
for each i in 0..49:
n[i] = i // initialise them to their indexes
nsize = 50 // starting pool size
do 6 times:
i = rnd(nsize) // give a number between 0 and nsize-1
print n[i]
nsize = nsize - 1 // these two lines effectively remove the used number
n[i] = n[nsize]
By simply selecting a random number from the pool, replacing it with the top number from that pool, then reducing the size of the pool, you get a shuffle without having to worry about a large number of swaps up front.
This is important if the number is high in that it doesn't introduce an unnecessary startup delay.
For example, examine the following bench-check, choosing 10-from-10:
<------ n[] ------>
0 1 2 3 4 5 6 7 8 9 nsize rnd(nsize) output
------------------- ----- ---------- ------
0 1 2 3 4 5 6 7 8 9 10 4 4
0 1 2 3 9 5 6 7 8 9 7 7
0 1 2 3 9 5 6 8 8 2 2
0 1 8 3 9 5 6 7 6 6
0 1 8 3 9 5 6 0 0
5 1 8 3 9 5 2 8
5 1 9 3 4 1 1
5 3 9 3 0 5
9 3 2 1 3
9 1 0 9
You can see the pool reducing as you go and, because you're always replacing the used one with an unused one, you'll never have a repeat.
Using the results returned from that as indexes into your collection will guarantee that no duplicate items will be selected.
var random = new Random();
var intArray = Enumerable.Range(0, 4).OrderBy(t => random.Next()).ToArray();
This array will contain 5 random numbers from 0 to 4.
or
var intArray = Enumerable.Range(0, 10).OrderBy(t => random.Next()).Take(5).ToArray();
This array will contain 5 random numbers between 0 to 10.
int firstNumber = intArray[0];
int secondNumber = intArray[1];
int thirdNumber = intArray[2];
int fourthNumber = intArray[3];
int fifthNumber = intArray[4];
For large sets of unique numbers, put them in an List..
Random random = new Random();
List<int> uniqueInts = new List<int>(10000);
List<int> ranInts = new List<int>(500);
for (int i = 1; i < 10000; i++) { uniqueInts.Add(i); }
for (int i = 1; i < 500; i++)
{
int index = random.Next(uniqueInts.Count) + 1;
ranInts.Add(uniqueInts[index]);
uniqueInts.RemoveAt(index);
}
Then randomly generate a number from 1 to myInts.Count. Store the myInt value and remove it from the List. No need to shuffle the list nor look to see if the value already exists.
instead of using List use Dictionary!!
In case it helps anyone else, I prefer allocating the minimum number of items necessary. Below, I make use of a HashSet, which ensures that new items are unique. This should work with very large collections as well, up to the limits of what HashSet plays nice with.
public static IEnumerable<int> GetRandomNumbers(int numValues, int maxVal)
{
var rand = new Random();
var yieldedValues = new HashSet<int>();
int counter = 0;
while (counter < numValues)
{
var r = rand.Next(maxVal);
if (yieldedValues.Add(r))
{
counter++;
yield return r;
}
}
}
generate unique random nos from 1 to 40 :
output confirmed :
class Program
{
static int[] a = new int[40];
static Random r = new Random();
static bool b;
static void Main(string[] args)
{
int t;
for (int i = 0; i < 20; i++)
{
lab: t = r.Next(1, 40);
for(int j=0;j<20;j++)
{
if (a[j] == t)
{
goto lab;
}
}
a[i] = t;
Console.WriteLine(a[i]);
}
Console.Read();
}
}
sample output :
7
38
14
18
13
29
28
26
22
8
24
19
35
39
33
32
20
2
15
37

Categories

Resources