Trying to get the number of times a sub query executes - c#

I have some code to sort an array into ascending order
int[] array = new int[] { 4, 3, 5, 1 };
var result = array.GroupBy(x => x)
.OrderBy(g => g.Count())
.ThenBy(g => g.Key)
.SelectMany(g => g);
I would like to be able to count the number of steps required to complete the sort.
The specific question I am trying to solve is this:
You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates. You are allowed to swap any two elements. You need to find the minimum number of swaps required to sort the array in ascending order.
Can I find the number of swaps used by LINQ?
Is it possible to get this?
So for example if the query had to swap 4 with 1 to get 1,3,5,4 then 5 with 4 to get 1,3,4,5 then this would be 2 steps.

This is how I came up. I couldn't find the way using it with LINQ however with our own Sorting Algorithm. I did something like this:
static void Main(string[] args)
{
ObservableCollection<int> array = new ObservableCollection<int>() {4,3,1,5 };
int steps = 0;
array.CollectionChanged+= (sender, e) =>
{
Console.WriteLine($"{e.Action} : {string.Join(",", array) }" );
steps++;
};
bool didSwap;
do
{
didSwap = false;
for (int i = 0; i < array.Count - 1; i++)
{
if (array[i] > array[i + 1])
{
int temp = array[i + 1];
array[i + 1] = array[i];
array[i] = temp;
didSwap = true;
}
}
} while (didSwap);
Console.WriteLine("Sorted Result :");
foreach(var item in array)
{
Console.WriteLine(item);
}
Console.WriteLine($"Total Swapps {steps / 2}");
Console.ReadLine();
}
This is the output:

Related

Find all index numbers of a value in array [duplicate]

This question already has answers here:
c# Array.FindAllIndexOf which FindAll IndexOf
(10 answers)
Closed 8 years ago.
How to find all positions of a value in array
class Program
{
static void Main(string[] args)
{
int start = 0;
int[] numbers = new int[7] { 2,1,2,1,5,6,5};
}
Something like that:
int[] numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
int toFind = 5;
// all indexes of "5" {4, 6}
int[] indexes = numbers
.Select((v, i) => new {
value = v,
index = i
})
.Where(pair => pair.value == toFind)
.Select(pair => pair.index)
.ToArray();
List<int> indexes = new List<int>();
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == yourNumber)
indexes.Add(i);
}
Useage is: Array.indexOf(T,value)
please refere to the msdn below.
http://msdn.microsoft.com/en-us/library/system.array.indexof(v=vs.110).aspx
You can make a really simple extension method for sequences to do this:
public static class SequenceExt
{
public static IEnumerable<int> IndicesOfAllElementsEqualTo<T>
(
this IEnumerable<T> sequence,
T target
) where T: IEquatable<T>
{
int index = 0;
foreach (var item in sequence)
{
if (item.Equals(target))
yield return index;
++index;
}
}
}
The extension method works with List<>, arrays, IEnumerable<T> and other collections.
Then your code would look something like this:
var numbers = new [] { 2, 1, 2, 1, 5, 6, 5 };
var indices = numbers.IndicesOfAllElementsEqualTo(5); // Use extension method.
// Make indices into an array if you want, like so
// (not really necessary for this sample code):
var indexArray = indices.ToArray();
// This prints "4, 6":
Console.WriteLine(string.Join(", ", indexArray));
Linq could help
var indexes = numbers
.Select((x, idx) => new { x, idx })
.Where(c => c.x == number)
.Select(c => c.idx);

Linq thenby running indefinitely

I have a function that is simply meant to print out a dictionary of frequent item sets in an easy-to-understand fashion. The goal is to order first by the size of the dictionary key and then by the lexicographical order of a list of numbers. The issue arises in the ThenBy statement as the commented out "hello" will get printed indefinitely. If I change the ThenBy to not use the comparer and simply use another int or string value, it works fine, so I'm clearly doing something wrong.
public static void printItemSets(Dictionary<List<int>, int> freqItemSet)
{
List<KeyValuePair<List<int>, int>> printList = freqItemSet.ToList();
printList = printList.OrderBy(x => x.Key.Count)
.ThenBy(x => x.Key, new ListComparer())
.ToList();
}
The code for the ListComparer is as follows:
public class ListComparer: IEqualityComparer<List<int>>, IComparer<List<int>>
{
public int Compare(List<int> a, List<int> b)
{
int larger = a.Count > b.Count ? 1: -1;
for (int i = 0; i < a.Count && i < b.Count; i++)
{
if (a[i] < b[i])
{
return -1;
}
else if (a[i] > b[i])
{
return 1;
}
else { }
}
return larger;
}
}
VERY simple test case:
int[] a = {1, 3, 5};
int[] b = { 2, 3, 5 };
int[] c = { 1, 2, 3, 5 };
int[] d = { 2, 5 };
int[] e = { 1, 3, 4 };
List<int> aL = a.ToList<int>();
List<int> bL = b.ToList<int>();
List<int> cL = c.ToList<int>();
List<int> dL = d.ToList<int>();
List<int> eL = e.ToList<int>();
Dictionary<List<int>, int> test = new Dictionary<List<int>, int>(new ListComparer());
test.Add(aL, 1);
test.Add(bL, 1);
test.Add(cL, 1);
test.Add(dL, 1);
test.Add(eL, 1);
The issue is that ListComparer is not checking if the arrays are the same. The same array is being passed in twice for both x and y. Checking if x and y are equal will resolve your issue.
Your comparer doesn't handle equal items. If the items are equal the order of the two items is what determines which is considered "larger". The comparer is thus not "reflexive". Being reflexive is a property sorting algorithms rely on.
The first line should be var larger = a.Count.CompareTo(b.Count); instead, so that truly equal lists will return 0 rather than either -1 or 1.

Equal values in array [duplicate]

This question already has answers here:
How to Count Duplicates in List with LINQ
(7 answers)
Closed 9 years ago.
How can I check if there are two or more equal values in one array?
eg. in this example, i want the program to tell me that there is a pair of 2 and a pair of 4
int[] array1 = { 1, 2, 4, 2, 4 };
Using Linq
var result = array1.GroupBy(i=>i)
.Select(g=>new {Value = g.Key, Count = g.Count()})
.Where(x=>x.Count>1)
.ToList();
foreach (var pair in result)
{
Console.WriteLine("PAIR: " + pair.Value + " COUNT: " + pair.Count);
}
[EDIT] Sorry, this answers the question "How can I check if there are two or more equal values in one array?", but it doesn't tell you the actual duplicates...
This would work, but possibly it isn't the most efficient way!
int[] array1 = { 1, 2, 4, 2, 4 };
if (array1.Distinct().Count() < array1.Length)
Console.WriteLine("Contains Dupes");
If you want the most efficient approach:
bool containsDupes(int[] array)
{
for (int i = 0; i < array.Length - 1; ++i)
{
int n = array[i];
for (int j = i+1; j < array.Length; ++j)
if (array[j] == n)
return true;
}
return false;
}
I don't think you can get much more efficient than that. It will return as soon as it finds any match.
You could use a Linq Statement like:
var query =
from numbers in array1
group numbers by numbers into duplicates
where duplicates.Count() > 1
select new { Item = duplicates.Key, ItemCount = duplicates.Count() };
This will return the following:
Item 2: ItemCount 2
Item 4: ItemCount 2
Or another syntax for the same:
var query = array1.GroupBy(x => x)
.Where(x => x.Count() > 1)
.Select(x => new { x, Count = x.Count() });
You could use LINQ's GroupBy
Example:
var grouped = array1.GroupBy(x => x).Select(x => new { Value = x.Key, Count = x.Count() });
foreach(var item in grouped) {
if (item.Count == 1)
continue;
Console.WriteLine("There are {0} instances of the number {1} in the array.", item.Count, item.Value);
}
I like this syntax:
int[] array1 = { 1, 2, 4, 2, 4 };
var isThereAnyRepeated = (from i in array1
group i by i into g
where g.Count() > 1
select g).Any();
Console.WriteLine(isThereAnyRepeated);
Here's a slight variation of I4V's answer.
Instead of Select and ToList this uses ToDictionary.
using System;
using System.Linq;
namespace StackOverflow_2013_05_27_EqualValuesInArray
{
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 4, 2, 4 };
var tbl = array
.GroupBy(n => n)
.Where(g => g.Count() > 1)
.ToDictionary(g => g.Key, g => g.Count());
foreach (var pair in tbl)
Console.WriteLine("{0} is in array {1} times", pair.Key, pair.Value);
Console.ReadLine();
}
}
}
class item
{
int value;
int number;
}
list<item> items = new list <item>();
for(int i=0; i<array1.length;i++)
{
if (i=0)
items.add(new item(array1[i],1))
else if (array1.contains(array[i])) items.add(new item(array1[i],))
else items.add(new item(array1[i],1))
}

Arrange MultiDimensional arrays to descending or ascending

I am trying to arrange this multidimensional array to ascending or descending. However, I need the relation between column 1 and 2 to still be together(meaning I need the data of eg. array[0,1] and array[0,2] to be together or related in some way or another. This are my codes as of right now.
int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
from y in Enumerable.Range(0, time.GetLength(1))
select new{
X = x,
Y = y,
Value = time[x,y]
}into point
orderby point.Value descending
select point;
This works but it splits all my data apart. Is there a way to sort them while keeping the relation of column 1 and 2 together?
I'm curious as to why you need a multidimensional array. It's clear you are treating your data as a single-dimensional collection of "rows," rather than a 2-dimensional collection of "cells."
Why not simply make a List(T), where T is some sort of Tuple or custom struct?
On the surface, it seems like you're trying to use a screwdriver on a nail; make sure you're picking the right tool for the job ;)
It sounds like you want to store your data in a multi-dimensional array, but keep each row in the array as a separate atomic unit. And additionally, the comparison of each "point" is by X, and then Y.
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
select new Point()
{
X = time[x,0],
Y = time[x,1]
} into point
orderby point.X ascending , point.Y ascending
select point;
int[,] sortedTime = new int[5,2];
int index = 0;
foreach (var testPoint in sorted)
{
Point aPoint = (Point) testPoint;
sortedTime.SetValue(aPoint.X, index, 0);
sortedTime.SetValue(aPoint.Y, index, 1);
index++;
}
It looks like you might just be overthinking things. If you want to keep the points together, and sort by the first column, for instance, just omit the second Enumerable.Range and assign the values by hand:
int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
select new{
X = time[x,0],
Y = time[x,1]
}into point
orderby point.X descending
select point;
As #Haxx points out, just add , point.Y descending to the orderby clause if the order of the second value is also important.
I also think that one should treat this as a collection of rows since you want rows to always stay together.
.NET has the DataTable type for that. E.g.
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 15, 10 }, { 3, 4 }, { 0, 2 } };
DataTable dt = new DataTable();
dt.Columns.Add("x", System.Type.GetType("System.Int32"));
dt.Columns.Add("y", System.Type.GetType("System.Int32"));
for (int i = 0; i < time.Length / 2; i++)
{
DataRow dr = dt.NewRow();
dr[0] = time[i, 0];
dr[1] = time[i, 1];
dt.Rows.Add(dr);
}
dt.DefaultView.Sort = "x" + " " + "ASC";
dt = dt.DefaultView.ToTable();
Note that I needed to type the table columns. Otherwise you'll get an alphabetical sort. I changed one of your numbers to 15 to demonstrate that the sort works on the integers (15>3, but alphabetically "15"<"3"). If you really want it back as a 2D array, see the first answer.
The fastest method would be to take implementation of some sorting algorithm like Quicksort and modify it to only use the Compare(i, j) and Swap(i, j) functions.
Then you can implement these functions for your multidimensional array and sort it in place.
Here is a working implementation:
public static void Main() {
int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };
DoSort(time);
}
public static void DoSort(int[,] data) {
Func<int, int, int> comparer = (i, j) => {
int s1 = Math.Sign(data[i, 0] - data[j, 0]);
if (s1 != 0) {
return s1;
}
int s2 = Math.Sign(data[i, 1] - data[j, 1]);
return s2;
};
Action<int, int> swapper = (i, j) => {
var tmp0 = data[i, 0];
var tmp1 = data[i, 1];
data[i, 0] = data[j, 0];
data[i, 1] = data[j, 1];
data[j, 0] = tmp0;
data[j, 1] = tmp1;
};
int length = data.GetLength(0);
Quicksort(comparer, swapper, 0, length - 1);
}
public static void Quicksort(Func<int, int, int> comparer, Action<int, int> swapper, int left, int right) {
int i = left, j = right;
int pivotIdx = (left + right) / 2;
while (i <= j) {
while (comparer(i, pivotIdx) < 0) {
i++;
}
while (comparer(j, pivotIdx) > 0) {
j--;
}
if (i <= j) {
swapper(i, j);
i++;
j--;
}
}
// Recursive calls
if (left < j) {
Quicksort(comparer, swapper, left, j);
}
if (i < right) {
Quicksort(comparer, swapper, i, right);
}
}
}
This code sorts the array in-place so you need no additional memory and in the end you get a sorted multidimensional array.
Assuming:
1. You want to keep the items paired, e.g. want to treat {0, 4} as one pair, {1, 5} as another pair.
2. The expected result in ascending order is: {{0, 2}, {0, 4}, {1, 5}, {3, 4}, {5, 10}}.
As suggested by BTownTKD, strongly recommend to use some class/struct to represent your pair instead of using multidimensional array. You can use a list/array of either of the following:
Tuple<int, int>
KeyValuePair<int, int>
your own struct IntPair, having two properties X and Y.
This will not only help you to sort, but also to do further manipulations easily. Use multidimensional array only if you have a very specific need to.
Here's sample code using Tuple:
List<Tuple<int, int>> time = new List<Tuple<int, int>>(){
new Tuple<int, int>(0,4),
new Tuple<int, int>(1,5),
new Tuple<int, int>(5,10),
new Tuple<int, int>(3,4),
new Tuple<int, int>(0,2)
};
//Sort Ascending
time.Sort((first, second) =>
{
var item1Compare = first.Item1.CompareTo(second.Item1);
return item1Compare == 0 ? first.Item2.CompareTo(second.Item2) : item1Compare;
});
//Sort Descending
/*time.Sort((first, second) =>
{
var item1Compare = second.Item1.CompareTo(first.Item1);
return item1Compare == 0 ? second.Item2.CompareTo(first.Item2) : item1Compare;
});*/

Finding if a target number is the sum of two numbers in an array via LINQ

A basic solution would look like this:
bool sortTest(int[] numbers, int target)
{
Array.Sort(numbers);
for(int i = 0; i < numbers.Length; i++)
{
for(int j = numbers.Length-1; j > i; j--)
{
if(numbers[i] + numbers[j] == target)
return true;
}
}
return false;
}
Now I'm very new to LINQ but this is what I have written so far:
var result = from num in numbers
where numbers.Contains(target -num)
select num;
if (result.Count() > 0)
return true;
return false;
Now i'm running into an issue given the following example:
Array: 1, 2, 4, 5, 8
Target: 16
It should return back false, but it's catching 16-8=8. So how do I go about not letting it notice itself in the contains check? Or can I make a second array each time within the query that doesn't contain the number I'm working with(thus solving the problem)?
Thanks in advance.
Is this what you're looking for?
var result = from n1 in numbers
from n2 in numbers
where n1 != n2 && n1 + n2 == target
select new { n1, n2 };
[Edit]
This returns matches twice and ignores the situation where a number is duplicated in the array. You can't handle these situations using Expression Syntax because you can't access the index of a matched item, but you can do it like this:
var result = numbers.Select((n1, idx) =>
new {n1, n2 = numbers.Take(idx).FirstOrDefault(
n2 => n1 + n2 == target)}).Where(pair => pair.n2 != 0);
As long as you don't have any zeros in your array.
[Further thought Edit]
The perfect mix solution:
var result = from item in numbers.Select((n1, idx) =>
new {n1, shortList = numbers.Take(idx)})
from n2 in item.shortList
where item.n1 + n2 == target
select new {n1 = item.n1, n2};
What I'd do to solve this problem in general is first write a "chooser".
public static IEnumerable<IEnumerable<T>> Chooser<T>(this IList<T> sequence, int num)
{ ... left as an exercise ... }
The output of the chooser is a sequence of sequences. Each sub-sequence is of length num, and consists of elements chosen from the original sequence. So if you passed { 10, 30, 20, 50 } as the sequence and 3 for num, you'd get the sequence of sequences:
{10, 30, 20}, {10, 30, 50}, {10, 20, 50}, {30, 20, 50}
as a result.
Once you've written Chooser, the problem becomes easy:
var results =
from subsequence in numbers.Chooser(2)
where subsequence.Sum() == target
select subsequence;
And now you can solve the problem for subsequences of other sizes, not just pairs.
Writing Chooser is a bit tricky but it's not too hard.
To improve on pdr's reply and address the concerns mentioned in the comments you could use the overloaded Select method to compare the indices of the items and ensure uniqueness.
public bool sortTest(int[] numbers, int target)
{
var indexedInput = numbers.Select((n, i) => new { Number = n, Index = i });
var result = from x in indexedInput
from y in indexedInput
where x.Index != y.Index
select x.Number + y.Number == target;
return result.Any(item => item);
}
Or in dot notation:
var result = numbers.Select((n, i) => new { Number = n, Index = i })
.SelectMany(
x => indexedInput,
(x, y) => new { x = x, y = y })
.Where(item => item.x.Index != item.y.Index)
.Select(item => item.x.Number + item.y.Number == target);

Categories

Resources