Unity how to compare contents of two arrays regardless of order? - c#

Looking for the most efficient way. I found this on comparing lists regardless of order:
https://answers.unity.com/questions/1307074/how-do-i-compare-two-lists-for-equality-not-caring.html
What about comparing array contents regardless of order?

You can use the Intersect method. Here is a simple console application
using System;
using System.Linq;
class Program
{
static void Main()
{
var nums1 = new int[] { 2, 4, 6, 8, 10, 9 };
var nums2 = new int[] { 1, 3, 6, 9, 12, 2 };
if (nums1.Intersect(nums2).Any()) // check if there is equal items
{
var equalItems = nums1.Intersect(nums2); // get list of equal items (2, 6, 9)
// ...
}
}
}

Related

How to sum List<int> values but only by cells in C#?

For example I have this as List<List<int>>:
[2,4,4,2,5]
[1,3,6,3,8]
[0,3,9,0,0]
Should return the sum but only taking cells assuming that the cell count is always the same:
[3, 10, 19, 5, 13]
I am trying to find an easy way to solve this using Linq if it is possible because I am doing this with a lot of for loops and if conditions and I am complicating myself.
Is there a possible way to achieve this using Linq?
Linq approach
List<List<int>> items = new List<List<int>>() {
new List<int> { 2, 4, 4, 2, 5 },
new List<int> { 1, 3, 6, 3, 8 },
new List<int> { 0, 3, 9, 0, 0 } };
List<int> result = Enumerable.Range(0, items.Min(x => x.Count)).Select(x => items.Sum(y => y[x])).ToList();
var xx = new List<List<int>>() {
new List<int>() { 2, 4, 4, 2, 5 },
new List<int>() { 1, 3, 6, 3, 8 },
new List<int>() { 0, 3, 9, 0, 0 },
};
var y = xx.Aggregate((r, x) => r.Zip(x).Select(p => p.First + p.Second).ToList());
I am doing this with a lot of for loops and if conditions and I am complicating myself.
You can accomplish it by using a single for loop.
Two possible approaches to achieve that are:
Approach 1
Creating an array with a capacity equal to the size of either of the lists in the original list collection
Filling the array with 0s
Looping through all lists in the original list collection, aggregating the sum for each index
Approach 2
Creating a list based on the first list in the original list collection
Looping through all subsequent lists in the original list collection, aggregating the sum for each index
Both approaches benefit from the assumption given in the question post:
[...] assuming that the cell count is always the same
If your original list collection is defined as a List<List<int>>:
List<List<int>> valuesCollection = new()
{
new() { 2, 4, 4, 2, 5 },
new() { 1, 3, 6, 3, 8 },
new() { 0, 3, 9, 0, 0 },
};
, the two approaches may be implemented as follows:
Approach 1
var indexCount = valuesCollection[0].Count;
var sums = new int[indexCount];
Array.Fill(sums, 0);
foreach (var values in valuesCollection)
{
for (var i = 0; i < sums.Length; i++)
{
sums[i] += values[i];
}
}
Approach 2
Note: Uses namespace System.Linq
var sums = valuesCollection[0].ToList();
foreach (var values in valuesCollection.Skip(1))
{
for (var i = 0; i < sums.Count; i++)
{
sums[i] += values[i];
}
}
Using either approach, sums's resulting content will be { 3, 10, 19, 5, 13 }.
Example fiddle here.

reversing an array using methods and MessageBox.show

I'm having issue with the following code:
public int ReverseArray(int[] rArray)
{
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };
Array.Reverse(array);
foreach (int value in array)
{
return (value);
}
return 0;
}
private void reverseButton_Click(object sender, EventArgs e)
{
int[] input = new int[10];
int output = ReverseArray(input);
MessageBox.Show(""+ output);
}
The code is supposed to take the given array (int[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };) and reverse it upon a button click; however, when I click on the reverseButton, I only get the number 8 and not the entire array. I'm sure it's the way my reversButton code is written, but I'm not sure how to fix it.
How can I fix my code to where when I click on reverseButton, the entire array will be displayed in reverse order?
You are not returning whole array back and also not iterating the array result and Array is a collection of items to you need to tell it to get each item one by one and print.
You can do something like following to make it work:
public int[] ReverseArray(int[] rArray)
{
Array.Reverse(array);
return array;
}
and in button click event you can use it:
int[] input = { 1, 2, 3, 4, 5, 6, 7, 8 };
input = ReverseArray(input);
string items = String.Join(",",input);
MessageBox.Show(items);
Because your method ReverseArray just returns one value:
public int[] ReverseArray(int[] rArray)
{
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };
Array.Reverse(array);
return array;
}
To show whole array you can combine it into some string:
int[] output = ReverseArray(input);
var message = string.Join(", ", output);
And show:
MessageBox.Show(message);

What is the option in C# having the same capability like 'IN' in SQL?

I want to search more than one condition in an if conditional block - the same like the IN operator does in SQL.
public class Check{
int [] arr = {1, 2, 5, 9, 7, 11, 89};
for (int i=0; i<arr.length; i++)
{
if(arr[i]==1||arr[i]==5||arr[i]==7||arr[i]==89)
{
Console.WriteLine("The number was found.");
}
}
Is there a solution for this kind of result?
if (arr[i] in(1, 5, 7, 89)
{
Console.WriteLine("The No Is Found.");
}
There's nothing in C# as a language that's equivalent to IN, no... but you can achieve a similar effect easily.
The simplest approach is to probably to use System.Linq and Contains against an array:
using System;
using System.Linq;
public class Check{
static void Main()
{
int[] candidates = {1, 2, 5, 9, 7, 11, 89};
// This is the members of the "in" clause - the
// the values you're trying to check against
int[] targets = { 1, 5, 7, 89 };
foreach (int candidate in candidates)
{
Console.WriteLine(
targets.Contains(candidate) ?
$"{candidate} is in targets" :
$"{candidate} is not in targets");
}
}
}
Alternatively, you could use a HashSet<int> - that would be more efficient if you had a large number of targets:
using System;
using System.Collections.Generic;
public class Check{
static void Main()
{
int[] candidates = {1, 2, 5, 9, 7, 11, 89};
var targets = new HashSet<int> { 1, 5, 7, 89 };
foreach (int candidate in candidates)
{
Console.WriteLine(
targets.Contains(candidate) ?
$"{candidate} is in targets" :
$"{candidate} is not in targets");
}
}
}

How do I pick values from an array without having repeating values in C# [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am using C# and I have an array that stores 20 integers.
I have 3 variables and I would like to assign them all to randomly-picked integers from the array, but I have to make it so that the values picked from the array are not the same.
Is there any way to do this other than by using a lot of if statements?
This answer is based on ThariqNugrohotomo's suggestion regarding selecting three distinct values from a shuffled array. I implemented a version of Fisher-Yates Shuffle algorithm, which is based on DotNetPerls example. The reason three distinct values are selected after the shuffle is performed is due to the fact that the source array may have repeating values. If we simply shuffle them, then there's a possibility of duplicates.
using System;
using System.Linq;
namespace ShuffleAndTakeUnique
{
public class Program
{
static Random _random = new Random();
static void Main(string[] args)
{
int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
var values = Shuffle<int>(array).Distinct().Take(3).ToArray();
foreach(var val in values)
{
Console.WriteLine(val);
}
}
public static T[] Shuffle<T>(T[] source)
{
T[] array = new T[source.Length];
Array.Copy(source, array, source.Length);
var random = _random;
for (int i = array.Length; i > 1; i--)
{
int j = random.Next(i);
T tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
}
return array;
}
}
}
Below are older ideas:
Here's a quick and dirty Console Application that stores three unique int values in a List<int>. You may then assign the values from that list to your variables. The list serves as a way to ensure uniqueness of the values. This is just an example, so obviously alter it to your needs and clean it up.
using System;
using System.Collections.Generic;
namespace App
{
class Program
{
static Random random = new Random();
static int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
static List<int> results = new List<int>();
static void Main(string[] args)
{
while (results.Count < 3)
{
int num = array[random.Next(array.Length)];
if (!results.Contains(num))
{
results.Add(num);
}
}
foreach(var result in results)
{
Console.WriteLine(result);
}
}
}
}
EDIT:
Here's an example that uses a generic method that will give you back an array of specified length (up to the maximum of the original array) that contains unique values from the original array:
using System;
using System.Collections.Generic;
using System.Linq;
namespace GetUniqueValues
{
class Program
{
static void Main(string[] args)
{
int[] array1 = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
var values1 = GetUniqueValues<int>(array1, 3);
foreach (var val in values1)
{
Console.WriteLine(val);
}
string[] array2 = { "apple", "orange", "cherry", "melon", "grapefruit", "grapes", "peach", "watermelon" };
var values2 = GetUniqueValues<string>(array2, 4);
foreach (var val in values2)
{
Console.WriteLine(val);
}
}
public static T[] GetUniqueValues<T>(T[] array, int valuesCount)
{
var values = new List<T>();
if (array != null && array.Length > 0 && valuesCount > 0)
{
var distinctCount = array.Distinct().Count();
if (valuesCount > distinctCount)
{
valuesCount = distinctCount;
}
var random = new Random();
while(values.Count < valuesCount)
{
T val = array[random.Next(array.Length)];
if (!values.Contains(val))
{
values.Add(val);
}
}
}
return values.ToArray();
}
}
}
Note that I make sure that the number of distinct values in the array is not less than the requested number of values. Otherwise, we'd be stuck in an infinite loop. If you pass an empty array or a count less than one, it will return an empty array. I prefer that over null... but once again, it's up to you.
Another way is to pass a copy of the original array as a List<T> and remove any occurrence of a value, once it's picked. That way, there is no way you can ever choose it again. Here's a quick, untested draft (I didn't test this at all), but you'll get the idea:
while(values.Count < valuesCount && list.Count > 0)
{
T val = list[random.Next(list.Count)];
values.Add(val);
list.RemoveAll(val);
}

LINQ for diffing sets

I have the following arrays:
var original= new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
enum Operation {Added,Removed}
I would like to execute a LINQ query that would return the following:
{{2,Removed},{4,Added}}
Limitation: I would like LINQ to perform this very efficiently and avoid and O(n^2) style algorithms.
Perhaps a LINQ solution is not the best option in this case.
This will produce a dictionary with the result that you want.
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
foreach (int value in original) {
difference.Add(value, Operation.Removed);
}
foreach (int value in target) {
if (difference.ContainsKey(value)) {
difference.Remove(value);
} else {
difference.Add(value, Operation.Added);
}
}
To keep the size of the dictionary down, perhaps it's possible to loop the enumerations in parallell. I'll have a look at that...
Edit:
Here it is:
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
IEnumerator<int> o = ((IEnumerable<int>)original).GetEnumerator();
IEnumerator<int> t = ((IEnumerable<int>)target).GetEnumerator();
bool oActive=true, tActive=true;
while (oActive || tActive) {
if (oActive && (oActive = o.MoveNext())) {
if (difference.ContainsKey(o.Current)) {
difference.Remove(o.Current);
} else {
difference.Add(o.Current, Operation.Removed);
}
}
if (tActive && (tActive = t.MoveNext())) {
if (difference.ContainsKey(t.Current)) {
difference.Remove(t.Current);
} else {
difference.Add(t.Current, Operation.Added);
}
}
}
Edit2:
I did some performance testing. The first version runs 10%-20% faster, both with sorted lists and randomly ordered lists.
I made lists with numbers from 1 to 100000, randomly skipping 10% of the numbers. On my machine the first version of the code matches the lists in about 16 ms.
enum Operation { Added, Removed, }
static void Main(string[] args)
{
var original = new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
var result = original.Except(target)
.Select(i => new { Value = i, Operation = Operation.Removed, })
.Concat(
target.Except(original)
.Select(i => new { Value = i, Operation = Operation.Added, })
);
foreach (var item in result)
Console.WriteLine("{0}, {1}", item.Value, item.Operation);
}
I don't think you can do this with LINQ using only a single pass given the stock LINQ extension methods but but might be able to code a custom extension method that will. Your trade off will likely be the loss of deferred execution. It would be interesting to compare the relative performance of both.
You are out of luck. If, as you stated in the comments, the lists are not sorted you can't compute the difference you seek in a single forward pass. Consider:
{ 1, 2, 3, 4, 5, 6, 7, ...
{ 1, 2, 3, 6, 7, 8, 9, ...
At the point where the first difference in encountered (4 vs. 6) it's impossible for you to determine if you are looking at the removal of 4 & 5 (as would be the case if both lists were monotonically increasing, or the insertion of 6, 7, 8, & 9 as would be the case if the lists continued like so:
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,...
{ 1, 2, 3, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9,...
This will achieve the result in a single pass, however I'm not sure of the complexity of the GroupBy operation.
var original= new int[] { 1, 2, 3 };
var target = new int[] { 1, 3, 4 };
var output = original.Select( i => new { I = i, L = "o" } )
.Concat( target.Select( i => new { I = i, L = "t" } ) )
.GroupBy( i => i.I ).Where( i => i.Count() == 1 )
.Select( i => new { I = i.Key, S = (i.ElementAt( 0 ).L == "o" ? Operation.Removed : Operation.Added) } );

Categories

Resources