Aggregate function. Sequence of steps - c#

Here is the simple task, and the solution, which uses aggregate function. I have a general idea of how to use this function (for example: counting sum of elements, multiplying numbers). However I can not figure out the exact sequence of steps in this solution.
We have array, which contains 4 distinct integer values and string with appearances of the array's indexes.
int[] nums = new int[] {1, 2, 3, 4};
string str = "123214";
We need to count number of appearances of each index, multiply by a corresponding value and then sum this all up, so that the answer would be 13.
Here is the solution, using aggregate function:
str.Aggregate(0, (i, c) => i + nums[c - '1']);
What is the sequence of steps that this function performs?

In this case you can solve this using eq. reasoning:
str.Aggregate(0, (i, c) => i + nums[c - '1'])
= "123214".Aggregate(0,(i,c) => i+nums[c-'1'])
(i := 0, c := '1' => 0+nums['1'-'1'] = 0+nums[0]=0+1 = 1)
= "23214".Aggregate(1, ...)
(i := 1, c := '2' => 1+nums[1]=1+2=3)
= "3214".Aggregate(3, ...)
(i := 3, c:='3' => 3+nums[2]=3+3=6)
= "214".Aggregate(6,...)
(i:=6, c:='2' => 6+nums[1]=6+2=8)
= "14".Aggregate(8,...)
(i:=8,c:='1' => 8+nums[0]=8+1=9)
= "4".Aggregate(9,...)
(i:=9,c:='4' => 9+nums[3]=9+4=13)
= "".Aggregate(13,...)
= 13
I hope this helps
To really learn things like this I would encourage you to look into functional programming (look for folds) - basically the first parameter in Aggregate is a state that gets passed around and second parameter is a function taking the old state and the next element in the enumeration (in this case the next character in your string) and has to produce a new state. So in your case the state is just a number and you calculate it by adding up the old state with a lookup from your nums array based on the numeric value of your character (as index).

Related

Should I use Sum method and Count/Length find the element of array that is the closest to the middle value of all elements?

If I have arr=[1,3,4,-7,9,11], the average value is (1+3+4-7+9+11) /6 = 3.5, then elements 3 and 4 are equally distant to 3.5, but smaller of them is 3 so 3 is the result.
You need to find out what the average is first. That involves a cycle either implemented explicitly, or invoked implicitly. So, let's assume that you already know what the average value is, because your question refers to the way some values related to the average can be obtained. Let's implement a comparison function:
protected bool isBetter(double a, double b, double avg) {
double absA = Abs(a - avg);
double absB = Abs(b - avg);
if (absA < absB) return a;
else if (absA > absB) return b;
return (a < b) ? a : b;
}
And now you can iterate your array, always compare via isBetter the current value with the best so far and if it's better, then it will be the new best. Whatever number ended up to be the best will be the result.
Assuming you have worked out the average (avg below) then you can get the diff for each item, then order by the diff, and get the first item. This will give you the closest item in the array
var nearestDiff = arr.Select(x => new { Value=x, Diff = Math.Abs(avg-x)})
.OrderBy(x => x.Diff)
.First().Value;
Live example: https://dotnetfiddle.net/iKvmhp
If instead you must get the item lower than the average
var lowerDiff = arr.Where(x => x<avg)
.OrderByDescending(x =>x)
.First();
You'll need using System.Linq for either of the above to work
Using GroupBy is a good way to do it
var arr = new int[] { 1, 4, 3, -7, 9, 11 };
var avg = arr.Average();
var result = arr.GroupBy(x=>Math.Abs(avg-x)).OrderBy(g=>g.Key).First().OrderBy(x=>x).First();
Original Array
[1,4,3,-7,9,11]
After grouping, key is abs distance from average, items are grouped according to that
[2.5, [1]]
[0.5, [4, 3]]
[5.5, [9]]
[7.5, [11]]
[10.5, [-7]]
Order by group keys
[0.5, [4, 3]]
[2.5, [1]]
[5.5, [9]]
[7.5, [11]]
[10.5, [-7]]
Take first group
[4, 3]
Order group items
[3, 4]
Take first item
3
changed array to [1,4,3,-7,9,11], reversing order of 3 and 4 because they are naturally ordered according to the output originally, and this is necessary to prove the last step

Get IndexOf Second int record in a sorted List in C#

I am having problem while trying to get First and Second Record (not second highest/lowest integer) Index from a sorted List. Lets say that list consists of three records that in order are like this: 0, 0, 1.
I tried like this:
int FirstNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(1).ToArray()[0]); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(MyList.OrderBy(item => item).Take(2).ToArray()[1]); //doesn't seem to work
As I explained, I am trying to get the indexes of first two zeros (they are not necessarily in ascending order before the sort) and not of zero and 1.
So if there was a list {0, 2, 4, 0} I need to get Indexes 0 and 3. But this may apply to any number that is smallest and repeats itself in the List.
However, it must also work when the smallest value does not repeat itself.
SecondNumberIndex is set to 0 because
MyList.OrderBy(item => item).Take(2).ToArray()[1] == 0
then you get
MyList.IndexOf(0)
that finds the first occurence of 0. 0 is equal to every other 0. So every time you ask for IndexOf(0), the very first 0 on the list gets found.
You can get what you want by using that sort of approach:
int FirstNumberIndex = MyList.IndexOf(0); //returns first record index, true
int SecondNumberIndex = MyList.IndexOf(0, FirstNumberIndex + 1 ); //will start search next to last ocurrence
From your code I guess you confuse some kind of "instance equality" with regular "equality".
Int is a simple type, IndexOf will not search for ocurrence of your specific instance of 0.
Keep in mind that this code, even if we will move in our thoughts to actual objects:
MyList.OrderBy(item => item).Take(2).ToArray()[1]
will not necessarily return equal objects in their original relative order from the input list.
EDIT
This cannot be adopted for general case, for getting indexes of ordered values from the original, unordered list.
If you are searching for indexes of any number of equal values, then setting bigger and bigger offset for the second parameter of IndexOf is OK.
But, let's consider a case when there are no duplicates. Such approach will work only when the input list is actually ordered ;)
You can preprocess your input list to have pairs (value = list[i],idx = i), then sort that pairs by value and then iterate over sorted pairs and print idx-es
You, probably, are asking about something like this:
var list = new List<int>{0,0,1};
var result = list.Select((val,i)=> new {value = val, idx = i}).Where(x=>x.value == 0);
foreach(var r in result) //anonymous type enumeration
Console.WriteLine(r.idx);
You can try user FindIndex.
var MyList = new List<int>() {3, 5, 1, 2, 4};
int firsIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(1).ToArray()[0]);
int secondIndex = MyList.FindIndex(a => a == MyList.OrderBy(item => item).Take(2).ToArray()[1]);
You could calculate the offset of the first occurrence, then use IndexOf on the list after skipping the offset.
int offset = ints.IndexOf(0) + 1;
int secondIndex = ints.Skip(offset).ToList().IndexOf(0) + offset;

Find smallest number in given range in an array

Hi i have an array of size N. The array values will always have either 1, 2, 3 integer values only. Now i need to find the lowest number between a given range of array indices. So for e.g. array = 2 1 3 1 2 3 1 3 3 2. the lowest value for ranges like [2-4] = 1, [4-5] = 2, [7-8] = 3, etc.
Below is my code :
static void Main(String[] args) {
string[] width_temp = Console.ReadLine().Split(' ');
int[] width = Array.ConvertAll(width_temp,Int32.Parse); // Main Array
string[] tokens_i = Console.ReadLine().Split(' ');
int i = Convert.ToInt32(tokens_i[0]);
int j = Convert.ToInt32(tokens_i[1]);
int vehicle = width[i];
for (int beg = i+1; beg <= j; beg++) {
if (vehicle > width[beg]) {
vehicle = width[beg];
}
}
Console.WriteLine("{0}", vehicle);
}
The above code works fine. But my concern is about efficiency. In above I am just taking one set of array range, but in actual there will be n number of ranges and I would have to return the lowest for each range. Now the problem is if there is a range like [0-N], N is array size, then I would end up comparing all the items for lowest. So I was wondering if there is a way around to optimize the code for efficiency???
I think it is a RMQ (Range Minimum Query) and there is several implementation which may fit your scenario.
Here is a nice TopCoder Tutorial cover a lot of them, I recommend two of them:
Using the notation in the tutorial, define <P, T> as <Preprocess Complexity, Query Complexity>, there is two famous and common implementation / data structure which can handle RMQ: Square Rooting Array & Segment Tree.
Segment Tree is famous yet hard to implement, it can solve RMQ in <O(n), O(lg n)> though, which has better complexity than Square Rooting Array (<O(n), O(sqrt(n))>)
Square Rooting Array (<O(n), O(sqrt(n))>)
Note That It is not a official name of the technique nor any data structure, indeed I do not know if there is any official naming of this technique since I learnt it...but here we go
For query time, it is definitely not the best you can got to solve RMQ, but it has an advantage: Easy Implementation! (Compared to Segment Tree...)
Here is the high level concept of how it works:
Let N be the length of the array, we split the array into sqrt(N) groups, each contain sqrt(N) elements.
Now we use O(N) time to find the minimum value of each groups, store them into another array call M
So using the above array, M[0] = min(A[0..2]), M[1] = min(A[3..5]), M[2] = min(A[6..8]), M[3] = min(A[9..9])
(The image from TopCoder Tutorial is storing the index of the minimum element)
Now let's see how to query:
For any range [p..q], we can always split this range into 3 parts at most.
Two parts for the left boundaries which is some left over elements that cannot be form a whole group.
One part is the elements in between, which forms some groups.
Using the same example, RMQ(2,7) can be split into 3 parts:
Left Boundary (left over elements): A[2]
Right Boundary (left over elements): A[6], A[7]
In between elements (elements across whole group): A[3],A[4],A[5]
Notice that for those in between elements, we have already preprocessed their minimum using M, so we do not need to look at each element, we can look and compare M instead, there is at most O(sqrt(N)) of them (it is the length of M afterall)
For boundary parts, as they cannot form a whole group by definition, means there is at most O(sqrt(N)) of them (it is the length of one whole group afterall)
So combining two boundary parts, with one part of in between elements, we only need to compare O(3*sqrt(N)) = O(sqrt(N)) elements
You can refer to the tutorial for more details (even for some pseudo codes).
You could do this using Linq extension methods.
List<int> numbers = new List<int> {2, 1, 3, 1, 2, 3, 1, 3, 3, 2};
int minindex =1, maxindex =3, minimum=-1;
if(minindex <= maxindex && maxindex>=0 && maxindex >=0 && maxindex < numbers.Count())
{
minimum = Enumerable.Range(minindex, maxindex-minindex+1) // max inclusive, remove +1 if you want to exclude
.Select(x=> numbers[x]) // Get the elements between given indices
.Min(); // Get the minimum among.
}
Check this Demo
This seems a fun little problem. My first point would be that scanning a fixed array tends to be pretty fast (millions per second), so you'd need a vast amount of data to warrant a more complex solution.
The obvious first thing, is to break from the loop when you have found a 1, as you've found your lowest value then.
If you want something more advanced.
Create a new array of int. Create a pre load function that populates each item of this array with the next index where it gets lower.
Create a loop that uses the new array to skip.
Here is what I mean. Take the following arrays.
int[] intialArray = new int[] { 3, 3, 3, 3, 2, 2, 2, 1 };
int[] searchArray = new int[] { 4, 4, 4, 4, 7, 7, 7, 7 };
So the idea is to find the lowest between positions 0-7.
Start at initialArray[0] and get value 3.
Read searchArray[0] and get the value 4. The 4 is the next index where the number is lower.
Read initialArray[4] and get the value 2.
etc.
So basically you'd need to put some effort to build the searcharray, but onces it's complete you would scan each range much faster.
Form your looping like the following:
int[] inputArray = { 2, 1, 3, 1, 2, 3, 1, 3, 3, 2 };
int minIndex = 2;
int maxIndex = 5;
int minVal = 3;
for (int i = minIndex; i <= maxIndex; i++)
{
if (inputArray[i] <= minVal)
minVal = inputArray[i];
}
Console.WriteLine("Minimum value in the Given range is ={0}", minVal);

Find equal or nearest smaller value from an array

Let's suppose I have this array (it is actually 255 long, values up to int.MaxValue):
int[] lows = {0,9,0,0,5,0,0,8,4,1,3,0,0,0,0};
From this array I would like to get index of a value equal or smaller to my number.
number = 7 -> index = 4
number = 2 -> index = 9
number = 8 -> index = 7
number = 9 -> index = 1
What would be the fastest way of finding it?
So far I've used linear search, but that turned out to be too inefficient for my need, because even though this array is only 255 long, values will be searched for a few million times.
I would need something equal to TreeSet.floor(E) used in java. I wanted to use Dictionary, but i don't know if it can find first smaller or equal value like I need.
Sort the array and then do a binary search to find the values.
See:
https://en.wikipedia.org/wiki/Binary_search
and
Array.BinarySearch Method
If it's not sorted (or otherwise held in a data structure where there is a relationship between the members that can assist the search), then you will have to examine every member to find the right one.
The easiest solution is probably to sort it and then do a binary chop/search to find the element matching your criteria.
If you want efficiency with the ability to still take unsorted arrays, maintain a sorted flag somewhere for the array (i.e., turn the whole thing into a class containing the indicator and the array) that indicates that the list is sorted.
Then you set this flag to false whenever the array is changed.
At the point where you want to do your search, you first check the sorted flag and sort the array if it's set to false (setting it to true as part of that process). If the flag is true, just bypass the sort.
That way, you only sort when needed. If the array hasn't changed since the last sort, there's no point in re-sorting.
You can also maintain the original unsorted list if the user needs that, keeping the sorted list as an additional array withing the class (another advantage of class-ifying your array). That way, you lose nothing. You have the original untouched data for the user to get at, and a fast means of efficiently find your desired element.
Your object (when sorted) would then contain:
int[] lows = {0,9,0,0,5,0,0,8,4,1,3,0,0,0,0};
int[] sortedlows = {0,0,0,0,0,0,0,0,0,1,3,4,5,8,9};
boolean isSorted = true;
If you then changed that_object[0] to 3, you'd end up with:
int[] lows = {3,9,0,0,5,0,0,8,4,1,3,0,0,0,0};
int[] sortedlows = {0,0,0,0,0,0,0,0,0,1,3,4,5,8,9};
boolean isSorted = false;
indicating that a sort would be needed before searching through sortedLows.
And keep in mind it's not a requirement to turn this into a class. If you're worried about it's performance (specifically accessing array elements through a getter method), you can maintain the arrays and flag yourself while still allowing direct access to the unsorted array. You just have to ensure that every place in your code that changes the array also sets the flag correctly.
But you should measure the performance before taking this path. The class-based way is "safer" since the object itself controls the whole thing.
First, normalise the data:
public static Dictionary<int, int> GetNormalised(int[] data)
{
var normalised = data.Select((value, index) => new { value, index })
.GroupBy(p => p.value, p => p.index)
.Where(p => p.Key != 0)
.OrderBy(p => p.Key)
.ToDictionary(p => p.Key, p => p.Min());
return normalised;
}
The search method:
public static int GetNearest(Dictionary<int, int> normalised, int value)
{
var res = normalised.Where(p => p.Key <= value)
.OrderBy(p => value - p.Key)
.Select(p => (int?)p.Value)
.FirstOrDefault();
if (res == null)
{
throw new ArgumentOutOfRangeException("value", "Not found");
}
return res.Value;
}
The unit test:
[TestMethod]
public void GetNearestTest()
{
var data = new[] { 0, 9, 0, 0, 5, 0, 0, 8, 4, 1, 3, 0, 0, 0, 0 };
var normalised = Program.GetNormalised(data);
var value = 7;
var expected = 4;
var actual = Program_Accessor.GetNearest(normalised, value);
Assert.AreEqual(expected, actual);
value = 2;
expected = 9;
actual = Program_Accessor.GetNearest(normalised, value);
Assert.AreEqual(expected, actual);
value = 8;
expected = 7;
actual = Program_Accessor.GetNearest(normalised, value);
Assert.AreEqual(expected, actual);
value = 9;
expected = 1;
actual = Program_Accessor.GetNearest(normalised, value);
Assert.AreEqual(expected, actual);
}
To optimise the performance cache all the used results.
To mock Java TreeSet in C#, use C# class: SortedDictionary or SortedSet; mock floor method in Java TreeSet, use LINQ method, to get minimum value.
SortedSet data = new SortedSet();
data.Where(p =>p < prices[i]).OrderByDescending(p=>p ).Take(1)
Based on HackerRank minimum cost algorithm, Java TreeSet implementation solution works fine, but C# SortedDictionary, SortedSet timeout.
Detail, see my coding blog: http://juliachencoding.blogspot.ca/2016/11/c-sorteddictionary-minimum-cost.html
So, C# SortedSet class GetViewBetween can do the same thing. See GetViewBetween API
There is a post: SortedSet / SortedList with better LINQ performance?

Optimizing this C# algorithm (K Difference)

This is the problem I'm solving (it's a sample problem, not a real problem):
Given N numbers , [N<=10^5] we need to count the total pairs of
numbers that have a difference of K. [K>0 and K<1e9]
Input Format: 1st line contains N & K (integers). 2nd line contains N
numbers of the set. All the N numbers are assured to be distinct.
Output Format: One integer saying the no of pairs of numbers that have
a diff K.
Sample Input #00:
5 2
1 5 3 4 2
Sample Output #00:
3
Sample Input #01:
10 1
363374326 364147530 61825163 1073065718 1281246024 1399469912 428047635 491595254 879792181 1069262793
Sample Output #01:
0
I already have a solution (and I haven't been able to optimize it as well as I had hoped). Currently my solution gets a score of 12/15 when it is run, and I'm wondering why I can't get 15/15 (my solution to another problem wasn't nearly as efficient, but got all of the points). Apparently, the code is run using "Mono 2.10.1, C# 4".
So can anyone think of a better way to optimize this further? The VS profiler says to avoid calling String.Split and Int32.Parse. The calls to Int32.Parse can't be avoided, although I guess I could optimize tokenizing the array.
My current solution:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace KDifference
{
class Solution
{
static void Main(string[] args)
{
char[] space = { ' ' };
string[] NK = Console.ReadLine().Split(space);
int N = Int32.Parse(NK[0]), K = Int32.Parse(NK[1]);
int[] nums = Console.ReadLine().Split(space, N).Select(x => Int32.Parse(x)).OrderBy(x => x).ToArray();
int KHits = 0;
for (int i = nums.Length - 1, j, k; i >= 1; i--)
{
for (j = 0; j < i; j++)
{
k = nums[i] - nums[j];
if (k == K)
{
KHits++;
}
else if (k < K)
{
break;
}
}
}
Console.Write(KHits);
}
}
}
Your algorithm is still O(n^2), even with the sorting and the early-out. And even if you eliminated the O(n^2) bit, the sort is still O(n lg n). You can use an O(n) algorithm to solve this problem. Here's one way to do it:
Suppose the set you have is S1 = { 1, 7, 4, 6, 3 } and the difference is 2.
Construct the set S2 = { 1 + 2, 7 + 2, 4 + 2, 6 + 2, 3 + 2 } = { 3, 9, 6, 8, 5 }.
The answer you seek is the cardinality of the intersection of S1 and S2. The intersection is {6, 3}, which has two elements, so the answer is 2.
You can implement this solution in a single line of code, provided that you have sequence of integers sequence, and integer difference:
int result = sequence.Intersect(from item in sequence select item + difference).Count();
The Intersect method will build an efficient hash table for you that is O(n) to determine the intersection.
Try this (note, untested):
Sort the array
Start two indexes at 0
If difference between the numbers at those two positions is equal to K, increase count, and increase one of the two indexes (if numbers aren't duplicated, increase both)
If difference is larger than K, increase index #1
If difference is less than K, increase index #2, if that would place it outside the array, you're done
Otherwise, go back to 3 and keep going
Basically, try to keep the two indexes apart by K value difference.
You should write up a series of unit-tests for your algorithm, and try to come up with edge cases.
This would allow you to do it in a single pass. Using hash sets is beneficial if there are many values to parse/check. You might also want to use a bloom filter in combination with hash sets to reduce lookups.
Initialize. Let A and B be two empty hash sets. Let c be zero.
Parse loop. Parse the next value v. If there are no more values the algorithm is done and the result is in c.
Back check. If v exists in A then increment c and jump back to 2.
Low match. If v - K > 0 then:
insert v - K into A
if v - K exists in B then increment c (and optionally remove v - K from B).
High match. If v + K < 1e9 then:
insert v + K into A
if v + K exists in B then increment c (and optionally remove v + K from B).
Remember. Insert v into B.
Jump back to 2.
// php solution for this k difference
function getEqualSumSubstring($l,$s) {
$s = str_replace(' ','',$s);
$l = str_replace(' ','',$l);
for($i=0;$i<strlen($s);$i++)
{
$array1[] = $s[$i];
}
for($i=0;$i<strlen($s);$i++)
{
$array2[] = $s[$i] + $l[1];
}
return count(array_intersect($array1,$array2));
}
echo getEqualSumSubstring("5 2","1 3 5 4 2");
Actually that's trivially to solve with a hashmap:
First put each number into a hashmap: dict((x, x) for x in numbers) in "pythony" pseudo code ;)
Now you just iterate through every number in the hashmap and check if number + K is in the hashmap. If yes, increase count by one.
The obvious improvement to the naive solution is to ONLY check for the higher (or lower) bound, otherwise you get the double results and have to divide by 2 afterwards - useless.
This is O(N) for creating the hashmap when reading the values in and O(N) when iterating through, i.e. O(N) and about 8loc in python (and it is correct, I just solved it ;-) )
Following Eric's answer, paste the implementation of Interscet method below, it is O(n):
private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource current in second)
{
set.Add(current);
}
foreach (TSource current2 in first)
{
if (set.Remove(current2))
{
yield return current2;
}
}
yield break;
}

Categories