C# Collection Group Related Elements - c#

I have a collection of points, I am attempting to write a function which groups all related points.
For example, related in this case means that an item contains the other:
int[] points = {2, 3, 4, 5, 6, 7, 2, 13, 14, 15, 32, 10, 237, 22, 46, 97}
getDirectRelatives(2) = {2, 2, 32, 237, 22}
This works for returning all directly related elements. But I would like to group the indirectly related elements. Since 3 and 7 have indirect relations to 2, I want all of their direct relations too:
getAllRelatives(2) = {2, 2, 32, 237, 22, 3, 13, 32, 7, 97}
Any suggestions?
Update: Here's my implementation to make it more clear. This works but I'd like to know if it's the correct approach
public void getAllRelatives()
{
int groupIndex = 1;
List<int> groupCollection = new List<int>();
bool flag = false;
int[] marked = null;
string currentOuter = null;
string currentInner = null;
List<int> current = new List<int>();
int[] points = {2, 4, 5, 6, 7, 2, 13, 14, 15, 32, 10, 237, 22, 46, 97};
//marked contains integers which identify which group an element belongs to
for (x = 0; x <= marked.Count - 1; x++) {
marked(x) = 0;
}
//Two loops. The first iterates over the target point, the second iterates over each sub point
//Once both loops are complete, groupCollection should contain the indexes for
//all related integers
//outerloop
for (i = 0; i <= points.Count - 1; i++) {
current.Clear();
currentOuter = points(i).ToString;
current.Add(i); //used to hold matches for current loop
//inner loop, targetpoint + 1 to end
for (x = i + 1; x <= points.Count - 1; x++) {
currentInner = points(x).ToString;
if (currentInner.Contains(currentOuter)) {
current.Add(x);
}
}
//if this is the first iteration, flag as true, forces current items to marked
if (marked(0) == 0) {
flag = true;
}
//check if any current points are marked and flag if any of the elements are already in a group, add each found group to group collection
for (x = 0; x <= current.Count - 1; x++) {
if (!(marked(current(x)) == 0)) {
flag = true;
groupCollection.Add(marked(current(x)));
}
}
if (flag == true) {
groupCollection.Add(groupIndex); //all relatives end up here
}
for (x = 0; x <= current.Count - 1; x++) {
marked(current(x)) = groupIndex;
}
groupIndex += 1;
flag = false;
}
}

convert int[] points to Dictionary<int, string[]> pointTokens
e.g.
pointTokens.Add(237, new string[]{"2", "3", "7"})
Then use pointTokens for finding relationships (how ever arbitary)
foreach(int point in pointTokens.Keys)
{
string[] tokens = pointTokens[point]
if(someInt.Equals(point))
{
// do something
}
if(tokens.Contains(someInt.ToString())
{
// do something
}
// etc ...
}

This is probably best solved as a graph theory question. You need to figure out how to create an appropriate graph to represent your data, and then traverse it for your answers.

Related

Last number in an array becomes first

I know that's easy, but I don't understand how I should do it.
1 23 29 18 43 20 5
to
5 1 23 29 18 43 20
I think we should use for-loop:
for (int i = 0; i < numbers.Count - 1; i++)
{
}
but I don't know what to do in it. Something like numbers[i] = numbers[i - 1] but it isn't working. I think there are some if checks which I miss.
The most straightforward way that comes to mind is a reverse loop.
int[] numbers = { 1, 23, 29, 18, 43, 20, 5};
int lastVal = numbers[numbers.Length - 1];
for (int i = numbers.Length -1; i > 0; i--)
numbers[i] = numbers[i-1];
numbers[0] = lastVal;
Just looping from the end (after saving the last value) and moving "up" the values, finally replacing the first value with the last
Here's a oneliner:
var numbers = new[] {1, 23, 29, 18, 43, 20, 5};
numbers = new[] {numbers.Last()}.Concat(numbers.Take(numbers.Length - 1)).ToArray();
This creates a new array containing the last element, then concatenates it with the original array excluding the last element.
What you want to do is make another array of the same size as the original one, then assign the last element and loop through the array up to the previous to last element.
Something like this:
int[] original = {1, 23, 29, 18, 43, 20, 5};
int[] altered = new int[original.length];
altered[0] = original[original.length - 1];
for (int i = 1; i < original.length - 1; i++)
{
altered[i] = original[i - 1];
}
You can perform a left rotation to the table by six positions on your case and create the requested new table
int[] myArray = new int[] { 1, 23, 29, 18, 43, 20, 5 };
var newArray = LeftRotationByD(myArray, 6);
and your function for the rotation would be:
private static int[] LeftRotationByD(int[] a, int k)
{
int[] b = new int[a.Length];
int index;
int length = a.Length;
int place;
for (int i = 0; i < length; i++)
{
index = i - k;
place = length + index;
if (index >= 0) b[index] = a[i];
else b[place] = a[i];
}
return b;
}
You can use this method to shift right:
void ShiftRight(int[] array, int count)
{
var clone = (int[])array.Clone();
for (var i = 0; i < array.Length; i++)
array[(i + count) % array.Length] = clone[i];
}
And use it this way:
var a = new int[] { 1, 2, 3, 4 };
ShiftRight(a, 1);

Why does array copying in this way not assign digits to the target array?

Why is this copying method not working? The target array should have digits greater than zero, tab2[0] = 3, tab2[1] = 4, etc.
int[] tab1 = { -2, 3, 4, - 5, 1, -7, -3, 4, 8, -10 };
int[] tab2 = new int[tab1.Length];
int a=0;
for (int i = 0; i < tab1.Length; i++)
{
if (tab1[i]>0)
{
tab2[a] = tab1[i];
a++;
}
richTextBox1.AppendText(tab2[i] + " ");
}
but this work
foreach (var item in tab1)
{
if (item>0)
{
tab2[a] = item;
a++;
}
}
Why is this copying method not working?
Actually copying is working but the problem is with the last line within for loop. There you are using wrong index i. There is also the problem that you are initializing destination array with the Length of the source array. It might lead to the trailing zeros in the destination array. I do propose to use List<int> it will simplify your code...and also move last line outside of the loop
int[] tab1 = { -2, 3, 4, - 5, 1, -7, -3, 4, 8, -10 };
List<int> tab2 = new List<int>(tab1.Length);
for (int i = 0; i < tab1.Length; i++)
{
if (tab1[i]>0)
{
tab2.Add(tab1[i]);
}
}
richTextBox1.AppendText(string.Join(" ", tab2);
int[] tab1 = { -2, 3, 4, - 5, 1, -7, -3, 4, 8, -10 };
int[] tab2 = new int[tab1.Length];
int a=0;
for (int i = 0; i < tab1.Length; i++)
{
if (tab1[i]>0)
{
tab2[a] = tab1[i];
richTextBox1.AppendText(tab2[a] + " ");
a++;
}
//I'm not sure why you put this outside the if statement.
//richTextBox1.AppendText(tab2[i] + " ");
}

Find Largest subarray( descending order)in a list of array c#

I need to find the largest subarray. For example: array list { 1, 4, 7, 3, -3, -4, -1, 4, 2, 1 } need to find the largest subarray where the numbers are decreasing.
As from the list { 7, 3, -3, -4 } is one subarray and { 4, 2, 1 }, as the earlier one is biggest need to print that.
Simply
var results = new List<int>();
for (var i = 0; i < input.Length; i++)
{
// how we check
var current = new List<int>();
// just to know if we are are going down
var lastValue = input[i];
// second loop make sure we stop if the numbers aren't going down
for (var j = i; j < input.Length && input[j] <= lastValue; j++)
{
current.Add(input[j]);
lastValue = input[j];
}
// Update the result depending on the criteria
if (current.Count >= results.Count)
{
results = current;
}
}
// print your awesome numbers
foreach (var value in results)
{
Console.Write($"{value}, ");
}
You can test it here
You could try this LINQ approach:
var array = new[] { 1, 4, 7, 3, -3, -4, -1, 4, 2, 1 };
var descending_subarrays =
array
.Skip(1)
.Aggregate(new [] { array.Take(1).ToList() }.ToList(), (a, x) =>
{
if (a.Last().Last() > x)
{
a.Last().Add(x);
}
else
{
a.Add(new [] { x }.ToList());
}
return a;
})
.OrderByDescending(x => x.Count)
.ToList();
That gives:
You can then just pick the find answer with a descending_subarrays.First().

How do I find duplicates in an array and display how many times they occurred?

I'm working on a code that prints out duplicated integers from an array with the number of their occurrence. I'm not allowed to use LINQ, just a simple code. I think I'm so close but confused about how to get a correct output:
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1;
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++)
{
if(array[j] == array[j+1])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
Console.ReadKey();
}
}
}
Since you can't use LINQ, you can do this with collections and loops instead:
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
var dict = new Dictionary<int, int>();
foreach(var value in array)
{
// When the key is not found, "count" will be initialized to 0
dict.TryGetValue(value, out int count);
dict[value] = count + 1;
}
foreach(var pair in dict)
Console.WriteLine("Value {0} occurred {1} times.", pair.Key, pair.Value);
Console.ReadKey();
}
Use Group by:
int[] values = new []{1,2,3,4,5,4,4,3};
var groups = values.GroupBy(v => v);
foreach(var group in groups)
Console.WriteLine("Value {0} has {1} items", group.Key, group.Count());
Let's take a look at a simpler example. Let's say we have the array {0, 0, 0, 0}.
What will your code do?
It will first look to see how many items after the first item are equal to it. There are three items after the first that are equal to it.
Then it goes to the next item, and looks for all items after it that are equal to it. There are two. So far we're at 5, and we haven't even finished yet (we have one more to add), but there are only four items in the whole array.
Clearly we have an issue here. We need to ensure that when we've searched the array for duplicates of a given item that we don't search through it again for that same item. While there are ways of doing that, this fundamental approach is looking to be quite a lot of work.
Of course, there are different approaches entirely that we can take. Rather that going through each item and searching for others like it, we can loop through the array once, and add to a count of number of times we've found that character. The use of a Dictionary makes this easy:
var dictionary = new Dictionary<int, int>();
foreach (int n in array)
{
if (!dictionary.ContainsKey(n))
dictionary[n] = 0;
dictionary[n]++;
}
Now we can just loop through the dictionary and see which values were found more than once:
foreach(var pair in dictionary)
if(pair.Value > 1)
Console.WriteLine(pair.Key);
This makes the code clear to read, obviously correct, and (as a bonus) quite a lot more efficient than your code, as you can avoid looping through the collection multiple times.
Here is an answer that avoids using Dictionaries. Since the OP said he is not familiar with them, this might give him a little insight into what Dictionaries do.
The downside to this answer is you have to enforce a limit on the max number in the array, and you can't have negative numbers. You'd never actually use this version in real code.
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int[] count = new int[13];
foreach(int number in array) {
// using the index of count same way you'd use a key in a dictionary
count[number]++;
}
foreach(int c in count) {
int numberCount = count[c];
if(numberCount > 0) {
Console.WriteLine(c + " occurs " + numberCount + " times");
}
}
int[] arr = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
var result = arr.GroupBy(x => x).Select(x => new { key = x.Key, val = x.Count() });
foreach (var item in result)
{
if(item.val > 1)
{
Console.WriteLine("Duplicate value : {0}", item.key);
Console.WriteLine("MaxCount : {0}", item.val);
}
}
Console.ReadLine();
Ok I have modified your code. This should do the job:
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
for (int i = 0; i < array.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
{
if (array[i] == array[j])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + " occurs " + count + " times");
}
Console.ReadKey();
}
}
/This is the answer that helps you to find the duplicate integer values using Forloop and it will return only the repeated values apart from its times of occurences/
public static void Main(string[] args)
{
//Array list to store all the duplicate values
int[] ary = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
ArrayList dup = new ArrayList();
for (int i = 0; i < ary.Length; i++)
{
for (int j = i + 1; j < ary.Length; j++)
{
if (ary[i].Equals(ary[j]))
{
if (!dup.Contains(ary[i]))
{
dup.Add(ary[i]);
}
}
}
}
Console.WriteLine("The numbers which duplicates are");
DisplayArray(dup);
}
public static void DisplayArray(ArrayList ary)
{
//loop through all the elements
for (int i = 0; i < ary.Count; i++)
{
Console.Write(ary[i] + " ");
}
Console.WriteLine();
Console.ReadKey();
}
public static void FindRepeating(int[] input)
{
for (var i = 0; i < input.Length; i++)
{
var abs = Math.Abs(input[i]);
if (input[abs] >= 0)
input[abs] = -input[abs];
else
Console.Write(abs + " ");
}
}
You made a minor mistake of using J instead of i ...
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1;
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++)
{
if(array[i] == array[j+1])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
Console.ReadKey();
}
}
}
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 7, 7, 8, 9, 7, 12, 12 };
Dictionary<int, int> duplicateNumbers = new Dictionary<int, int>();
int count=1;
for (int i = 0; i < array.Length; i++)
{
count=1;
if(!duplicateNumbers.ContainsKey(array[i]))
{
for (int j = i; j < array.Length-1; j++)
{
if (array[i] == array[j+1])
{
count++;
}
}
if (count > 1)
{
duplicateNumbers.Add(array[i], count);
}
}
}
foreach (var num in duplicateNumbers)
{
Console.WriteLine("Duplicate numbers, NUMBER-{0}, OCCURRENCE- {1}",num.Key,num.Value);
}
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
/// <summary>
/// How do you find the duplicate number on a given integer array?
/// </summary>
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
Dictionary<int, int> duplicates = FindDuplicate(array);
Display(duplicates);
Console.ReadLine();
}
private static Dictionary<T, int> FindDuplicate<T>(IEnumerable<T> source)
{
HashSet<T> set = new HashSet<T>();
Dictionary<T, int> duplicates = new Dictionary<T, int>();
foreach (var item in source)
{
if (!set.Add(item))
{
if (duplicates.ContainsKey(item))
{
duplicates[item]++;
}
else
{
duplicates.Add(item, 2);
}
}
}
return duplicates;
}
private static void Display(Dictionary<int, int> duplicates)
{
foreach (var item in duplicates)
{
Console.WriteLine($"{item.Key}:{item.Value}");
}
}
}
}
int[] arr = { 1, 2, 3, 2, 4, 5, 2, 4 };
var duplicates = arr.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Item = y.Key, Count = y.Count() })
.ToList();
Console.WriteLine(String.Join("\n", duplicates));
This approach, fixed up, will give the correct output (it's highly inefficient, but that's not a problem unless you're scaling up dramatically.)
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
for (int i = 0; i < array.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length ; j++)
{
if(array[i] == array[j])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + " occurs " + count);
Console.ReadKey();
}
I counted 5 errors in the OP code, noted below.
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1; // 1. have to put "count" in the inner loop so it gets reset
// 2. have to start count at 0
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++) // 3. have to cover the entire loop
// for (int j=0 ; j<array.Length ; j++)
{
if(array[j] == array[j+1]) // 4. compare outer to inner loop values
// if (array[i] == array[j])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
// 5. It's spelled "occurs" :)
Console.ReadKey();
}
Edit
For a better approach, use a Dictionary to keep track of the counts. This allows you to loop through the array just once, and doesn't print duplicate counts to the console.
var counts = new Dictionary<int, int>();
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
for (int i = 0; i < array.Length; i++)
{
int currentVal = array[i];
if (counts.ContainsKey(currentVal))
counts[currentVal]++;
else
counts[currentVal] = 1;
}
foreach (var kvp in counts)
Console.WriteLine("\t\n " + kvp.Key + " occurs " + kvp.Value);
class Program
{
static void Main(string[] args)
{
int[] arr = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
List<int> nums = new List<int>();
List<int> count = new List<int>();
nums.Add(arr[0]);
count.Add(1);
for (int i = 1; i < arr.Length; i++)
{
if(nums.Contains(arr[i]))
{
count[nums.IndexOf(arr[i])] += 1;
}
else
{
nums.Add(arr[i]);
count.Add(1);
}
}
for(int x =0; x<nums.Count;x++)
{
Console.WriteLine("number:"+nums[x] +"Count :"+ count[x]);
}
Console.Read();
}
}

C# For Loop with Random Int Generator locks the program

I have 2 one dimensional arrays, containing the exact same values:
public int[] start = new int[21] { 0, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14 };
public int[] end = new int[21] { 0, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14 };
Below is the code I use to generate a random index, and grab the element from the array with said index, and stick it in a 2D array, with randomly generated X and Y index.
for (int i = 0; i < 21; i++)
{
Random ranNum = new Random();
int genX = 0;
int genY = 5;
int indx = 1;
while (gameBoard[genX, genY].rank > -1)
{
genX = ranNum.Next(0, 9);
genY = ranNum.Next(5, 8);
}
while (start[indx] == -1)
{
indx = ranNum.Next(0, 21);
}
if (gameBoard[genX, genY].rank == -1)
{
gameBoard[genX, genY].rank = start[indx];
start[indx] = -1;
}
while (gameBoard[genX, genY].rank > -1)
{
genX = ranNum.Next(0, 9);
genY = ranNum.Next(0, 3);
}
while (end[indx] == -1)
{
indx = ranNum.Next(0, 21);
}
if (gameBoard[genX, genY].rank == -1)
{
gameBoard[genX, genY].rank = end[indx];
end[indx] = -1;
}
}
Basically, it takes a value from the "start" and "end" arrays, replaces them with a '-1' (so they don't get picked again), scans the 2D array for '-1s' (so it doesn't place the number in a location that already has one), and places it there.
Notice that the min and max value for the random are different for the "start" and "end" arrays. This is to ensure that they end up far away from each other, on the other side of the 2D array.
This code works. Now, I have a code that resets all the variables back to their previous state. A reset function which also works. See, if the user is not content with the random placement, they can reset the arrays, and randomize again.
At which point the program simply hangs / locks up. No error, no messages, it just stops working. Please, could you share any ideas on how / why this happens?
Note: If I remove the entire while loop concerning the "end" array, the program can randomize and reset all it wants.
Anyway, the code for the reset:
int resVal = 0;
for (int i = 0; i < 21; i++)
{
startBoard[i] = resVal;
enemyBoard[i] = resVal;
if (i == 0)
resVal++;
else if (i >= 6 && i < 19)
resVal++;
}
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 9; x++)
{
gameBoard[x, y] = new classPiece();
gameBoard[x, y].rank = -1;
}
}
Move Random ranNum = new Random(); out of the cycle.

Categories