An integer array as a key for Dictionary - c#

I wish to have the dictionary which uses an array of integers as keys, and if the integer array has the same value (even different object instance), they will be treated as the same key. How should I do it?
The following code does not work as b is different object instances.
int[] a = new int[] { 1, 2, 3 };
int[] b = new int[] { 1, 2, 3 };
Dictionary<int[], string> dic = new Dictionary<int[], string>();
dic.Add(a, "haha");
string output = dic[b];

You can create an IEqualityComparer to define how the dictionary should compare items. If the ordering of items is relevant, then something like this should work:
public class MyEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
if (x.Length != y.Length)
{
return false;
}
for (int i = 0; i < x.Length; i++)
{
if (x[i] != y[i])
{
return false;
}
}
return true;
}
public int GetHashCode(int[] obj)
{
int result = 17;
for (int i = 0; i < obj.Length; i++)
{
unchecked
{
result = result * 23 + obj[i];
}
}
return result;
}
}
Then pass it in as you create the dictionary:
Dictionary<int[], string> dic
= new Dictionary<int[], string>(new MyEqualityComparer());
Note: calculation of hash code obtained here:
What is the best algorithm for an overridden System.Object.GetHashCode?

Maybe you should consider using a Tuple
var myDictionary = new Dictionary<Tuple<int,int>, string>();
myDictionary.Add(new Tuple<int,int>(3, 3), "haha1");
myDictionary.Add(new Tuple<int,int>(5, 5), "haha2");
According to MSDN , Tuple objects Equals method will use the values of the two Tuple objects

The easiest way if you don't care about actual hashing may just be to convert the array into a string. Adding a space to avoid numbers joining.
dic.Add(String.Join(" ",a), "haha");

Related

Dictionary as key of another Dictionary / count number of equal Dictionarys

I want to use a Dictionary as the key of another Dictionary, but the comparision for equal keys shall not use the reference for comparision, but the Dictionary's content. How can I do this?
Here is what I currently have: I want to know how many equal histograms (implemented as Dictionary) I have. For that I create another Dictionary numberOfHistogramOccurences with the histograms as key, the value shall then be increased by one on each new addition of a histogram with equal content.
I am also open for hints on other ways of counting content-equal histograms/Dictionaries.
// define two histograms with equal content
Dictionary<int, int>[] histograms = new Dictionary<int, int>[2];
histograms[0] = new Dictionary<int, int>();
histograms[0][0] = 3;
histograms[0][5] = 1;
histograms[0][10] = 8;
histograms[1] = new Dictionary<int, int>();
histograms[1][0] = 3;
histograms[1][5] = 1;
histograms[1][10] = 8;
// use the equal histograms as key.
// as they are reference types, their reference is compared and not their content ):
var numberOfHistogramOccurences = new Dictionary<Dictionary<int, int>, int>();
foreach (var histogram in histograms)
{
if (!numberOfHistogramOccurences.ContainsKey(histogram))
numberOfHistogramOccurences[histogram] = 0;
numberOfHistogramOccurences[histogram]++;
}
// this gives two different keys;
// I need one key with a value of 2,
// as both histograms are equal
Debug.WriteLine("Number of different keys in numberOfHistogramOccurences: " + numberOfHistogramOccurences.Keys.Count);
Following my comment, using a custom comparer. Note that I added another histogram in order to check that it sees differences as well.
public static void Main()
{
// define two histograms with equal content
Dictionary<int, int>[] histograms = new Dictionary<int, int>[2];
histograms[0] = new Dictionary<int, int>();
histograms[0][0] = 3;
histograms[0][5] = 1;
histograms[0][10] = 8;
histograms[1] = new Dictionary<int, int>();
histograms[1][0] = 3;
histograms[1][5] = 1;
histograms[1][10] = 8;
histograms[2] = new Dictionary<int, int>();
histograms[2][0] = 1;
histograms[2][5] = 3;
histograms[2][10] = 8;
// use the equal histograms as key.
// as they are reference types, their reference is compared and not their content ):
/* change this line */
var numberOfHistogramOccurences = new Dictionary<Dictionary<int, int>, int>(new HistogramComparer());
/* ---------------- */
foreach (var histogram in histograms)
{
if (!numberOfHistogramOccurences.ContainsKey(histogram))
numberOfHistogramOccurences[histogram] = 0;
numberOfHistogramOccurences[histogram]++;
}
// this gives two different keys;
// I need one key with a value of 2,
// as both histograms are equal
Debug.WriteLine("Number of different keys in numberOfHistogramOccurences: " + numberOfHistogramOccurences.Keys.Count);
}
And the custom comparer class HistogramComparer:
public class HistogramComparer : IEqualityComparer<Dictionary<int, int>>
{
public bool Equals(Dictionary<int, int> x, Dictionary<int, int> y)
{
// check that y contains all x.Keys
foreach (var key in x.Keys)
if (!y.Keys.Contains(key))
return false;
// check that x contains all y.Keys
foreach (var key in y.Keys)
if (!x.Keys.Contains(key))
return false;
// check that keys have same values
foreach (var entry in x)
if (y[entry.Key] != entry.Value)
return false;
return true;
}
public int GetHashCode(Dictionary<int, int> obj)
{
int hash = 0;
foreach (var entry in obj)
hash ^= (entry.Key ^ entry.Value);
return hash;
}
}

Extract integers from 2D Arraylist whose sum is between a range

I'm writing code for a .NETMF application and need to create a function which accepts 2 params int min, int max and returns an array of integers returnedArr from a generated 2D Arraylist arr were the sum of integers inside returnedArr will be between min and max and also I will not know what the size or contents of arr will be prior to calling the method. Only 1 integer per Arraylist inside arr will be selected.
public ArrayList GetNums(int min, int max)
{
//arr will be structured like this
//var arr = new ArrayList
//{
// new ArrayList {10, 34, 56, 60},
// new ArrayList {3, 23, 56, 78, 65, 42},
// new ArrayList {53, 56, 76}
//};
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
A sample would be GetNums(130,140);
Return arraylist could be Arraylist{56,23,53}
Also bear in mind that I'm confined to using Arraylists so I can't use generic lists, I was thinking that some sort of foreach loop would do the job but can't get my head around how this would work since I no idea what the size of arr will be before hand
-----------SAMPLE 'arr' VALUES---------
var arr = new ArrayList
{
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 60,100,140,180},
new ArrayList { 41,43,45,55,81,83,85,95,121,123,125,135},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,57,63}
};
If the 'arr' is not huge, using recursion and brute force:
public ArrayList GetNums(int min, int max, ArrayList arr)
{
var results = new ArrayList();
//nothing in the arr?
if (arr.Count == 0)
return results;
//arr has only one list inside
if(arr.Count == 1)
{
foreach(int a in (ArrayList)arr[0])
{
if(a >= min && a <= max)
{
var r = new ArrayList();
r.Add(a);
results.Add(r);
}
}
return results;
}
//arr has two or more lists inside
ArrayList firstList = (ArrayList)arr[0];
ArrayList remainingArr = new ArrayList();
for(int i = 1; i < arr.Count; i++)
{
remainingArr.Add(arr[i]);
}
foreach (int a in firstList)
{
var tempResults = GetNums(min - a, max - a, remainingArr);
foreach(ArrayList result in tempResults)
{
var newResult = new ArrayList();
newResult.Add(a);
newResult.AddRange(result);
results.Add(newResult);
}
}
return results;
}
The result is a list of solutions. First valid solution for your example arr is {10, 65, 56}
If it is acceptable to have the same result, of the minimum values, each and every time, then what you could do is to:
start with the smallest value of each sub-array,
sort the remaining values, tracking their source sub-array,
and move up the sorted values until you've met or exceeded the specified min
An example of such functionality (using LINQ for brevity, and converting back to ArrayList) would be as such:
public static ArrayList GetNums(int min, int max)
{
var arr = GenerateArraylistValues();
// Initialize our results with the minimum values from each array.
var results = arr.Cast<ArrayList>().Select(sub => sub.Cast<int>().Min()).ToList();
var others = new List<UnionItem>();
for (int i = 0; i < arr.Count; i++)
{
others = new List<UnionItem>(others
// Concatenate the arrays together.
.Union(((ArrayList)arr[i]).Cast<int>()
// Don't need the min value, which we will start at already. (Optional)
.Where(val => val != results[i])
// Create the UnionItem, to hold the value and the original array source.
.Select(val => new UnionItem(val, i))));
}
// Order our combined values.
others = new List<UnionItem>(others.OrderBy(val => val.Value));
using (var next = others.GetEnumerator())
{
// Progress through the combined values until we (a) meet or exceed min, or (b) run out of values.
while ((results.Sum() < min) && (next.MoveNext()))
{
// Update the list of result values according to the UnionItem source.
results[next.Current.Source] = next.Current.Value;
}
}
// Once through our calculation, check now if we've successfully met the conditions.
int sum = results.Sum();
if (sum >= min && sum <= max)
{
return new ArrayList(results);
}
else
{
// Whatever happens if no valid match.
return new ArrayList();
}
}
private class UnionItem
{
public readonly int Value; // Holds the value from the array.
public readonly int Source; // Holds the index of the source array.
public UnionItem(int value, int source)
{
Value = value;
Source = source;
}
}
I've created the UnionItem class, simply so we can do the tracking of the source array for each value, to substitute back correctly our results.

fastest way for accessing double array as key in dictionary

I have a double[] array, i want to use it as key (not literally, but in the way that the key is matched when all the doubles in the double array need to be matched)
What is the fastest way to use the double[] array as key to dictionary?
Is it using
Dictionary<string, string> (convert double[] to a string)
or
anything else like converting it
Given that all key arrays will have the same length, either consider using a Tuple<,,, ... ,>, or use a structural equality comparer on the arrays.
With tuple:
var yourDidt = new Dictionary<Tuple<double, double, double>, string>();
yourDict.Add(Tuple.Create(3.14, 2.718, double.NaN), "da value");
string read = yourDict[Tuple.Create(3.14, 2.718, double.NaN)];
With (strongly typed version of) StructuralEqualityComparer:
class DoubleArrayStructuralEqualityComparer : EqualityComparer<double[]>
{
public override bool Equals(double[] x, double[] y)
{
return System.Collections.StructuralComparisons.StructuralEqualityComparer
.Equals(x, y);
}
public override int GetHashCode(double[] obj)
{
return System.Collections.StructuralComparisons.StructuralEqualityComparer
.GetHashCode(obj);
}
}
...
var yourDict = new Dictionary<double[], string>(
new DoubleArrayStructuralEqualityComparer());
yourDict.Add(new[] { 3.14, 2.718, double.NaN, }, "da value");
string read = yourDict[new[] { 3.14, 2.718, double.NaN, }];
Also consider the suggestion by Sergey Berezovskiy to create a custom class or (immutable!) struct to hold your set of doubles. In that way you can name your type and its members in a natural way that makes it more clear what you do. And your class/struct can easily be extended later on, if needed.
Thus all arrays have same length and each item in array have specific meaning, then create class which holds all items as properties with descriptive names. E.g. instead of double array with two items you can have class Point with properties X and Y. Then override Equals and GetHashCode of this class and use it as key (see What is the best algorithm for an overriding GetHashCode):
Dictionary<Point, string>
Benefits - instead of having array, you have data structure which makes its purpose clear. Instead of referencing items by indexes, you have nice named property names, which also make their purpose clear. And also speed - calculating hash code is fast. Compare:
double[] a = new [] { 12.5, 42 };
// getting first coordinate a[0];
Point a = new Point { X = 12.5, Y = 42 };
// getting first coordinate a.X
[Do not consider this a separate answer; this is an extension of #JeppeStigNielsen's answer]
I'd just like to point out that you make Jeppe's approach generic as follows:
public class StructuralEqualityComparer<T>: IEqualityComparer<T>
{
public bool Equals(T x, T y)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
}
public int GetHashCode(T obj)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
}
public static StructuralEqualityComparer<T> Default
{
get
{
StructuralEqualityComparer<T> comparer = _defaultComparer;
if (comparer == null)
{
comparer = new StructuralEqualityComparer<T>();
_defaultComparer = comparer;
}
return comparer;
}
}
private static StructuralEqualityComparer<T> _defaultComparer;
}
(From an original answer here: https://stackoverflow.com/a/5601068/106159)
Then you would declare the dictionary like this:
var yourDict = new Dictionary<double[], string>(new StructuralEqualityComparer<double[]>());
Note: It might be better to initialise _defaultComparer using Lazy<T>.
[EDIT]
It's possible that this might be faster; worth a try:
class DoubleArrayComparer: IEqualityComparer<double[]>
{
public bool Equals(double[] x, double[] y)
{
if (x == y)
return true;
if (x == null || y == null)
return false;
if (x.Length != y.Length)
return false;
for (int i = 0; i < x.Length; ++i)
if (x[i] != y[i])
return false;
return true;
}
public int GetHashCode(double[] data)
{
if (data == null)
return 0;
int result = 17;
foreach (var value in data)
result += result*23 + value.GetHashCode();
return result;
}
}
...
var yourDict = new Dictionary<double[], string>(new DoubleArrayComparer());
Ok this is what I found so far:
I input an entry (length 4 arrray) to the dictionary, and access it for 999999 times on my machine:
Dictionary<double[], string>(
new DoubleArrayStructuralEqualityComparer()); takes 1.75 seconds
Dictionary<Tuple<double...>,string> takes 0.85 seconds
The code below takes 0.1755285 seconds, which is the fastest now! (in line with the comment with Sergey.)
The fastest - The code of DoubleArrayComparer by Matthew Watson takes 0.15 seconds!
public class DoubleArray
{
private double[] d = null;
public DoubleArray(double[] d)
{
this.d = d;
}
public override bool Equals(object obj)
{
if (!(obj is DoubleArray)) return false;
DoubleArray dobj = (DoubleArray)obj;
if (dobj.d.Length != d.Length) return false;
for (int i = 0; i < d.Length; i++)
{
if (dobj.d[i] != d[i]) return false;
}
return true;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
for (int i = 0; i < d.Length;i++ )
{
hash = hash*23 + d[i].GetHashCode();
}
return hash;
}
}
}

in C#, how do I order items in a list where the "largest" values are in the middle of the list

I have been stumped on this one for a while. I want to take a List and order the list such that the Products with the largest Price end up in the middle of the list. And I also want to do the opposite, i.e. make sure that the items with the largest price end up on the outer boundaries of the list.
Imagine a data structure like this.. 1,2,3,4,5,6,7,8,9,10
In the first scenario I need to get back 1,3,5,7,9,10,8,6,4,2
In the second scenario I need to get back 10,8,6,4,2,1,3,5,7,9
The list may have upwards of 250 items, the numbers will not be evenly distributed, and they will not be sequential, and I wanted to minimize copying. The numbers will be contained in Product objects, and not simple primitive integers.
Is there a simple solution that I am not seeing?
Any thoughts.
So for those of you wondering what I am up to, I am ordering items based on calculated font size. Here is the code that I went with...
The Implementation...
private void Reorder()
{
var tempList = new LinkedList<DisplayTag>();
bool even = true;
foreach (var tag in this) {
if (even)
tempList.AddLast(tag);
else
tempList.AddFirst(tag);
even = !even;
}
this.Clear();
this.AddRange(tempList);
}
The Test...
[TestCase(DisplayTagOrder.SmallestToLargest, Result=new[]{10,14,18,22,26,30})]
[TestCase(DisplayTagOrder.LargestToSmallest, Result=new[]{30,26,22,18,14,10})]
[TestCase(DisplayTagOrder.LargestInTheMiddle, Result = new[] { 10, 18, 26, 30, 22, 14 })]
[TestCase(DisplayTagOrder.LargestOnTheEnds, Result = new[] { 30, 22, 14, 10, 18, 26 })]
public int[] CalculateFontSize_Orders_Tags_Appropriately(DisplayTagOrder sortOrder)
{
list.CloudOrder = sortOrder;
list.CalculateFontSize();
var result = (from displayTag in list select displayTag.FontSize).ToArray();
return result;
}
The Usage...
public void CalculateFontSize()
{
GetMaximumRange();
GetMinimunRange();
CalculateDelta();
this.ForEach((displayTag) => CalculateFontSize(displayTag));
OrderByFontSize();
}
private void OrderByFontSize()
{
switch (CloudOrder) {
case DisplayTagOrder.SmallestToLargest:
this.Sort((arg1, arg2) => arg1.FontSize.CompareTo(arg2.FontSize));
break;
case DisplayTagOrder.LargestToSmallest:
this.Sort(new LargestFirstComparer());
break;
case DisplayTagOrder.LargestInTheMiddle:
this.Sort(new LargestFirstComparer());
Reorder();
break;
case DisplayTagOrder.LargestOnTheEnds:
this.Sort();
Reorder();
break;
}
}
The appropriate data structure is a LinkedList because it allows you to efficiently add to either end:
LinkedList<int> result = new LinkedList<int>();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Array.Sort(array);
bool odd = true;
foreach (var x in array)
{
if (odd)
result.AddLast(x);
else
result.AddFirst(x);
odd = !odd;
}
foreach (int item in result)
Console.Write("{0} ", item);
No extra copying steps, no reversing steps, ... just a small overhead per node for storage.
C# Iterator version
(Very simple code to satisfy all conditions.)
One function to rule them all! Doesn't use intermediate storage collection (see yield keyword). Orders the large numbers either to the middle, or to the sides depending on the argument. It's implemented as a C# iterator
// Pass forward sorted array for large middle numbers,
// or reverse sorted array for large side numbers.
//
public static IEnumerable<long> CurveOrder(long[] nums) {
if (nums == null || nums.Length == 0)
yield break; // Nothing to do.
// Move forward every two.
for (int i = 0; i < nums.Length; i+=2)
yield return nums[i];
// Move backward every other two. Note: Length%2 makes sure we're on the correct offset.
for (int i = nums.Length-1 - nums.Length%2; i >= 0; i-=2)
yield return nums[i];
}
Example Usage
For example with array long[] nums = { 1,2,3,4,5,6,7,8,9,10,11 };
Start with forward sort order, to bump high numbers into the middle.
Array.Sort(nums); //forward sort
// Array argument will be: { 1,2,3,4,5,6,7,8,9,10,11 };
long[] arrLargeMiddle = CurveOrder(nums).ToArray();
Produces: 1 3 5 7 9 11 10 8 6 4 2
Or, Start with reverse sort order, to push high numbers to sides.
Array.Reverse(nums); //reverse sort
// Array argument will be: { 11,10,9,8,7,6,5,4,3,2,1 };
long[] arrLargeSides = CurveOrder(nums).ToArray();
Produces: 11 9 7 5 3 1 2 4 6 8 10
Significant namespaces are:
using System;
using System.Collections.Generic;
using System.Linq;
Note: The iterator leaves the decision up to the caller about whether or not to use intermediate storage. The caller might simply be issuing a foreach loop over the results instead.
Extension Method Option
Optionally change the static method header to use the this modifier public static IEnumerable<long> CurveOrder(this long[] nums) { and put it inside a static class in your namespace;
Then call the order method directly on any long[ ] array instance like so:
Array.Reverse(nums); //reverse sort
// Array argument will be: { 11,10,9,8,7,6,5,4,3,2,1 };
long[] arrLargeSides = nums.CurveOrder().ToArray();
Just some (unneeded) syntactic sugar to mix things up a bit for fun. This can be applied to any answers to your question that take an array argument.
I might go for something like this
static T[] SortFromMiddleOut<T, U>(IList<T> list, Func<T, U> orderSelector, bool largestInside) where U : IComparable<U>
{
T[] sortedArray = new T[list.Count];
bool add = false;
int index = (list.Count / 2);
int iterations = 0;
IOrderedEnumerable<T> orderedList;
if (largestInside)
orderedList = list.OrderByDescending(orderSelector);
else
orderedList = list.OrderBy(orderSelector);
foreach (T item in orderedList)
{
sortedArray[index] = item;
if (add)
index += ++iterations;
else
index -= ++iterations;
add = !add;
}
return sortedArray;
}
Sample invocations:
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] sortedArray = SortFromMiddleOut(array, i => i, false);
foreach (int item in sortedArray)
Console.Write("{0} ", item);
Console.Write("\n");
sortedArray = SortFromMiddleOut(array, i => i, true);
foreach (int item in sortedArray)
Console.Write("{0} ", item);
With it being generic, it could be a list of Foo and the order selector could be f => f.Name or whatever you want to throw at it.
The fastest (but not the clearest) solution is probably to simply calculate the new index for each element:
Array.Sort(array);
int length = array.Length;
int middle = length / 2;
int[] result2 = new int[length];
for (int i = 0; i < array.Length; i++)
{
result2[middle + (1 - 2 * (i % 2)) * ((i + 1) / 2)] = array[i];
}
Something like this?
public IEnumerable<int> SortToMiddle(IEnumerable<int> input)
{
var sorted = new List<int>(input);
sorted.Sort();
var firstHalf = new List<int>();
var secondHalf = new List<int>();
var sendToFirst = true;
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current);
}
else
{
secondHalf.Add(current);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
return firstHalf.Concat(secondHalf);
}
For your specific (general) case (assuming unique keys):
public static IEnumerable<T> SortToMiddle<T, TU>(IEnumerable<T> input, Func<T, TU> getSortKey)
{
var sorted = new List<TU>(input.Select(getSortKey));
sorted.Sort();
var firstHalf = new List<TU>();
var secondHalf = new List<TU>();
var sendToFirst = true;
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current);
}
else
{
secondHalf.Add(current);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
sorted = new List<TU>(firstHalf.Concat(secondHalf));
//This assumes the sort keys are unique - if not, the implementation
//needs to use a SortedList<TU, T>
return sorted.Select(s => input.First(t => s.Equals(getSortKey(t))));
}
And assuming non-unique keys:
public static IEnumerable<T> SortToMiddle<T, TU>(IEnumerable<T> input, Func<T, TU> getSortKey)
{
var sendToFirst = true;
var sorted = new SortedList<TU, T>(input.ToDictionary(getSortKey, t => t));
var firstHalf = new SortedList<TU, T>();
var secondHalf = new SortedList<TU, T>();
foreach (var current in sorted)
{
if (sendToFirst)
{
firstHalf.Add(current.Key, current.Value);
}
else
{
secondHalf.Add(current.Key, current.Value);
}
sendToFirst = !sendToFirst;
}
//to get the highest values on the outside just reverse
//the first list instead of the second
secondHalf.Reverse();
return(firstHalf.Concat(secondHalf)).Select(kvp => kvp.Value);
}
Simplest solution - order the list descending, create two new lists, into the first place every odd-indexed item, into the other every even indexed item. Reverse the first list then append the second to the first.
Okay, I'm not going to question your sanity here since I'm sure you wouldn't be asking the question if there weren't a good reason :-)
Here's how I'd approach it. Create a sorted list, then simply create another list by processing the keys in order, alternately inserting before and appending, something like:
sortedlist = list.sort (descending)
biginmiddle = new list()
state = append
foreach item in sortedlist:
if state == append:
biginmiddle.append (item)
state = prepend
else:
biginmiddle.insert (0, item)
state = append
This will give you a list where the big items are in the middle. Other items will fan out from the middle (in alternating directions) as needed:
1, 3, 5, 7, 9, 10, 8, 6, 4, 2
To get a list where the larger elements are at the ends, just replace the initial sort with an ascending one.
The sorted and final lists can just be pointers to the actual items (since you state they're not simple integers) - this will minimise both extra storage requirements and copying.
Maybe its not the best solution, but here's a nifty way...
Let Product[] parr be your array.
Disclaimer It's java, my C# is rusty.
Untested code, but you get the idea.
int plen = parr.length
int [] indices = new int[plen];
for(int i = 0; i < (plen/2); i ++)
indices[i] = 2*i + 1; // Line1
for(int i = (plen/2); i < plen; i++)
indices[i] = 2*(plen-i); // Line2
for(int i = 0; i < plen; i++)
{
if(i != indices[i])
swap(parr[i], parr[indices[i]]);
}
The second case, Something like this?
int plen = parr.length
int [] indices = new int[plen];
for(int i = 0; i <= (plen/2); i ++)
indices[i] = (plen^1) - 2*i;
for(int i = 0; i < (plen/2); i++)
indices[i+(plen/2)+1] = 2*i + 1;
for(int i = 0; i < plen; i++)
{
if(i != indices[i])
swap(parr[i], parr[indices[i]]);
}

How to remove duplicates from int[][]

I have an array of arrays - information about selection in Excel using VSTO, where each element means start and end selection position.
For example,
int[][] selection = {
new int[] { 1 }, // column A
new int[] { 6 }, // column F
new int[] { 6 }, // column F
new int[] { 8, 9 } // columns H:I
new int[] { 8, 9 } // columns H:I
new int[] { 12, 15 } // columns L:O
};
Could you please help me to find a way, maybe using LINQ or Extension methods, to remove duplicated elements? I mean: F and F, H:I and H:I, etc.
If you want to use a pure LINQ/extension method solution, then you'll need to define your own implementation of IEqualityComparer for arrays/sequences. (Unless I'm missing something obvious, there's no pre-existing array or sequence comparer in the BCL). This isn't terribly hard however - here's an example of one that should do the job pretty well:
public class SequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return Enumerable.SequenceEqual(x, y);
}
// Probably not the best hash function for an ordered list, but it should do the job in most cases.
public int GetHashCode(IEnumerable<T> obj)
{
int hash = 0;
int i = 0;
foreach (var element in obj)
hash = unchecked((hash * 37 + hash) + (element.GetHashCode() << (i++ % 16)));
return hash;
}
}
The advantage of this is that you can then simply call the following to remove any duplicate arrays.
var result = selection.Distinct(new SequenceEqualityComparer<int>()).ToArray();
Hope that helps.
First you need a way to compare the integer arrays. To use it with the classes in the framework, you do that by making an EquailtyComparer. If the arrays are always sorted, that is rather easy to implement:
public class IntArrayComparer : IEqualityComparer<int[]> {
public bool Equals(int[] x, int[] y) {
if (x.Length != y.Length) return false;
for (int i = 0; i < x.Length; i++) {
if (x[i] != y[i]) return false;
}
return true;
}
public int GetHashCode(int[] obj) {
int code = 0;
foreach (int value in obj) code ^= value;
return code;
}
}
Now you can use an integer array as key in a HashSet to get the unique arrays:
int[][] selection = {
new int[] { 1 }, // column A
new int[] { 6 }, // column F
new int[] { 6 }, // column F
new int[] { 8, 9 }, // columns H:I
new int[] { 8, 9 }, // columns H:I
new int[] { 12, 15 } // columns L:O
};
HashSet<int[]> arrays = new HashSet<int[]>(new IntArrayComparer());
foreach (int[] array in selection) {
arrays.Add(array);
}
The HashSet just throws away duplicate values, so it now contains four integer arrays.

Categories

Resources