Okay, so this seems simple, but I can't think of a straightforward solution;
Basically I have an object array in C# that contains, say, 102 elements. I then also have 4 other empty arrays. I want to iterate through the original array and distribute the 100 elements evenly, then distribute 101 and 102 to the 1st and 2nd new arrays respectively.
int i = 1,a=0, b=0, c=0, d = 0;
foreach (ReviewStatus data in routingData)
{
if (i == 1)
{
threadOneWork[a] = data;
a++;
}
if (i == 2)
{
threadTwoWork[b] = data;
b++;
}
if (i == 3)
{
threadThreeWork[c] = data;
c++;
}
if (i == 4)
{
threadFourWork[d] = data;
d++;
i = 0;
}
i++;
}
Now the above code definitely works, but I was curious, does anybody know of a better way to do this??
var workArrays = new[] {
threadOneWork,
threadTwoWork,
threadThreeWork,
threadFourWork,
};
for(int i=0; i<routingData.Length; i++) {
workArrays[i%4][i/4] = routingData[i];
}
Put the four arrays into an array of arrays, and use i%4 as an index. Assuming that thread###Work arrays have enough space to store the data, you can do this:
var tw = new[] {threadOneWork, threadTwoWork, threadThreeWork, threadFourWork};
var i = 0;
foreach (ReviewStatus data in routingData) {
tw[i%4][i/tw.Length] = data;
i++;
}
Linq is your friend! Use modulo to group the items via the total number of arrays in your case 4.
For example the code splits them up into four different lists:
var Items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Items.Select( ( i, index ) => new {
category = index % 4,
value = i
} )
.GroupBy( itm => itm.category, itm => itm.value )
.ToList()
.ForEach( gr => Console.WriteLine("Group {0} : {1}", gr.Key, string.Join(",", gr)));
/* output
Group 0 : 1,5,9
Group 1 : 2,6,10
Group 2 : 3,7
Group 3 : 4,8
*/
Related
Im working from the Q https://www.testdome.com/for-developers/solve-question/10282
Write a function that, given a list and a target sum, returns zero-based indices of any two distinct elements whose sum is equal to the target sum. If there are no such elements, the function should return null.
For example, FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12) should return a Tuple<int, int> containing any of the following pairs of indices:
1 and 4 (3 + 9 = 12)
2 and 3 (5 + 7 = 12)
3 and 2 (7 + 5 = 12)
4 and 1 (9 + 3 = 12)
So far iv got:
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
//throw new NotImplementedException("Waiting to be implemented.");
IList<int> duplicateList = list;
foreach (int i in list)
{
foreach (int j in duplicateList)
{
if (i != j)
{
if (i + j == sum)
{
return Tuple.Create(i, j);
}
}
}
}
return null;
}
public static void Main(string[] args)
{
Tuple<int, int> indices = FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12);
Console.WriteLine(indices.Item1 + " " + indices.Item2);
}
}
This returns the correct answer in my code but is failing 3 out of 4 cases in the quesitong because:
Example case: Wrong answer
No solution: Correct answer
One solution: Wrong answer
Performance test with a large number of elements: Wrong answer
Ive looked at the hints
Hint 1: Nested for loops can iterate over the list and calculate a sum in O(N^2) time.
Hint 2: A dictionary can be used to store pre-calculated values, this may allow a solution with O(N) complexity.
So im using nested loops but Im guessing in this instance in order to pass hint2 I need to use a dictionary...How can I refactor this into using a dictionary?
Thanks for any help!
You are not returning indexes, you are returning values. for loops are not foreach loops.
A nested for loops solution would be something like this:
for(int i=0; i<list.Count-1; i++)
{
for(int j=i+1;j<list.Count;j++)
{
if(list[i]+list[j] == sum)
{
return Tuple.Create(i, j);
}
}
}
return null;
I'll leave the dictionary solution for you to create.
Hi this one received 50%
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
int n = list.Count-1;
while(n != 0)
{
for (int i = 0; i <= list.Count-1 ; i++)
{
if (list[n] + list[i] == sum)
{
return Tuple.Create(i, n);
}
}
n--;
}
return null;
}
// get list value:
var aat = (from l1 in list
from l2 in list
where l1 + l2 == 12
group new { l1, l2} by new { l1, l2 } into gp
select new {gp.Key}).ToDictionary( a => a.Key.l1, b => b.Key.l2 );
// get list index of the value:
var aav = (from l1 in list
from l2 in list
where l1 + l2 == 12
group new { l1, l2 } by new { l1, l2 } into gp
select new { gp.Key })
.ToDictionary( a => list.IndexOf(a.Key.l1), b => list.IndexOf(b.Key.l2)
);
I want to create a new group when the difference between the values in rows are greater then five.
Example:
int[] list = {5,10,15,40,45,50,70,75};
should give me 3 groups:
1,[ 5,10,15 ]
2,[40,45,50]
3,[70,75]
Is it possible to use Linq here?
Thx!
Exploiting side effects (group) is not a good practice, but can be helpful:
int[] list = { 5, 10, 15, 40, 45, 50, 70, 75 };
int step = 5;
int group = 1;
var result = list
.Select((item, index) => new {
prior = index == 0 ? item : list[index - 1],
item = item,
})
.GroupBy(pair => Math.Abs(pair.prior - pair.item) <= step ? group : ++group,
pair => pair.item);
Test:
string report = string.Join(Environment.NewLine, result
.Select(chunk => String.Format("{0}: [{1}]", chunk.Key, String.Join(", ", chunk))));
Outcome:
1: [5, 10, 15]
2: [40, 45, 50]
3: [70, 75]
Assuming collection has an indexer defined, can be something like this:
const int step = 5;
int currentGroup = 1;
var groups = list.Select((item, index) =>
{
if (index > 0 && item - step > list[index - 1])
{
currentGroup++;
}
return new {Group = currentGroup, Item = item};
}).GroupBy(i => i.Group).ToList();
In my opinion, just write a function to do it. This is easier to understand and more readable than the Linq examples given in other answers.
public static List<List<int>> Group(this IEnumerable<int> sequence, int groupDiff) {
var groups = new List<List<int>>();
List<int> currGroup = null;
int? lastItem = null;
foreach (var item in sequence) {
if (lastItem == null || item - lastItem.Value > groupDiff) {
currGroup = new List<int>{ item };
groups.Add(currGroup);
} else {
// add item to current group
currGroup.Add(item);
}
lastItem = item;
}
return groups;
}
And call it like this
List<List<int>> groups = Group(list, 5);
Assumption: list is sorted. If it is not sorted, just sort it first and use the above code.
Also: if you need groups to be an int[][] just use the Linq Method ToArray() to your liking.
for each element that their difference with former is less than three, order them in descending
numbers = {1,2,3,4,5,6,13,18,25,30,31,32,33}
desired = {6,5,4,3,2,1,13,18,25,33,32,31,30}
for example in numbers list ,Because difference between 6 and 5 is less than 3 sort them in descending
You can use LINQ:
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 13, 18, 25, 30, 31, 32, 33 };
var result = numbers.GroupAdjacent((x, y) => y - x < 3)
.SelectMany(g => g.OrderByDescending(x => x))
.ToArray();
// result == { 6, 5, 4, 3, 2, 1, 13, 18, 25, 33, 32, 31, 30 }
with
static IEnumerable<IEnumerable<T>> GroupAdjacent<T>(
this IEnumerable<T> source, Func<T, T, bool> adjacent)
{
var g = new List<T>();
foreach (var x in source)
{
if (g.Count != 0 && !adjacent(g.Last(), x))
{
yield return g;
g = new List<T>();
}
g.Add(x);
}
yield return g;
}
hello that is too complex..
As i dont have the Visual studio so i wrote the code in javascript that will cover your requirement
<script>
var a = [1,2,3,4,5,6,13,18,25,30,31,32,33];
alert(custom_sort(a));
function custom_sort(a) {
var objArrayList = {};
var index = 0;
var where_i_am = 0;
objArrayList[index] = Array();
if(a[1]-a[0] < 3){
where_i_am = 1;
objArrayList[index].push(a[0]);
} else {
where_i_am = 2;
objArrayList[index].push(a[0]);
}
for(var i=1;i<a.length;i++) {
if(a[i]-a[i-1] < 3) {
if(where_i_am ==2) {
where_i_am = 1;
index++;
objArrayList[index] = Array();
}
if(where_i_am==1)
objArrayList[index].push(a[i]);
} else {
if(where_i_am==1) {
where_i_am =2;
index++;
objArrayList[index] = Array();
}
if(where_i_am==2) {
objArrayList[index].push(a[i]);
}
}
}
var new_array = new Array();
for(var obj in objArrayList) {
var array_val = objArrayList[obj];
if(array_val[1] - array_val[0] < 3) {
new_array = new_array.concat(sort_desc(array_val));
} else {
new_array = new_array.concat(sort_asc(array_val));
}
}
return new_array;
}
function sort_asc(array_val){
for(var i =0;i<array_val.length;i++) {
for(var j=0;j<array_val.length;j++) {
if(array_val[i] < array_val[j]) {
var temp = array_val[i];
array_val[i] = array_val[j];
array_val[j] = temp;
}
}
}
return array_val;
}
function sort_desc(array_val){
for(var i =0;i<array_val.length;i++) {
for(var j=0;j<array_val.length;j++) {
if(array_val[i] > array_val[j]) {
var temp = array_val[i];
array_val[i] = array_val[j];
array_val[j] = temp;
}
}
}
return array_val;
}
</script>
For me such algorithm looks very non standard so I feel there are few algorithms should be used to achieve good results in terms of complexity. There is one very important question - does an initial array already sorted?
Any way you can start by splitting array by sub arrays:
Split such array to multiple (with some indicator whether each one should be sorted
ASC or DESC)
Then if an initial array is not sorted:
Then sort all of sub arrays one by one using QuickSort, so you will get a set of sorted arrays
Then you can sort sub arrays using the first element of each so order of sub arrays should be saved (Hope I described it clear enough)
But if an initial array was sorted:
Merge sub arrays in initially preserved order
I was looking for some fast and efficient method do merge items in array. This is my scenario. The collection is sorted by From. Adjacent element not necessarily differ by 1, that is there can be gaps between the last To and the next From, but they never overlap.
var list = new List<Range>();
list.Add(new Range() { From = 0, To = 1, Category = "AB" });
list.Add(new Range() { From = 2, To = 3, Category = "AB" });
list.Add(new Range() { From = 4, To = 5, Category = "AB" });
list.Add(new Range() { From = 6, To = 8, Category = "CD" });
list.Add(new Range() { From = 9, To = 11, Category = "AB" }); // 12 is missing, this is ok
list.Add(new Range() { From = 13, To = 15, Category = "AB" });
I would like the above collection to be merged in such way that the first three (this number can vary, from at least 2 elements to as many as the condition is satisfied) elements become one element. Cannot merge elements with different category.
new Range() { From = 0, To = 5, Category = "AB" };
So that the resulting collection would have 4 elements total.
0 - 5 AB
6 - 8 CD
9 - 11 AB // no merging here, 12 is missing
13 - 15 AB
I have a very large collection with over 2.000.000 items and I would like to this as efficiently as possible.
Here's a generic, reusable solution rather than an ad hoc, specific solution.
(Updated based on comments)
IEnumerable<T> Merge<T>(this IEnumerable<T> coll,
Func<T,T,bool> canBeMerged, Func<T,T,T>mergeItems)
{
using(IEnumerator<T> iter = col.GetEnumerator())
{
if (iter.MoveNext())
{
T lhs = iter.Current;
while(iter.MoveNext())
{
T rhs = iter.Current;
if (canBeMerged(lhs, rhs)
lhs=mergeItems(lhs, rhs);
else
{
yield return lhs;
lhs= rhs;
}
}
yield return lhs;
}
}
}
You will have to provide method to determine if the item can be merged, and to merge them.
These really should be part of your Range class, so it would be called like them:
list.Merge((l,r)=> l.IsFollowedBy(r), (l,r)=> l.CombineWith(r));
If you don't have these method, then you would have to call it like:
list.Merge((l,r)=> l.Category==r.Category && l.To +1 == r.From,
(l,r)=> new Range(){From = l.From, To=r.To, Category = l.Category});
Well, from the statement of the problem I think it is obvious that you cannot avoid iterating through the original collection of 2 million items:
var output = new List<Range>();
var currentFrom = list[0].From;
var currentTo = list[0].To;
var currentCategory = list[0].Category;
for (int i = 1; i < list.Count; i++)
{
var item = list[i];
if (item.Category == currentCategory && item.From == currentTo + 1)
currentTo = item.To;
else
{
output.Add(new Range { From = currentFrom, To = currentTo,
Category = currentCategory });
currentFrom = item.From;
currentTo = item.To;
currentCategory = item.Category;
}
}
output.Add(new Range { From = currentFrom, To = currentTo,
Category = currentCategory });
I’d be interested to see if there is a solution more optimised for performance.
Edit: I assumed that the input list is sorted. If it is not, I recommend sorting it first instead of trying to fiddle this into the algorithm. Sorting is only O(n log n), but if you tried to fiddle it in, you easily get O(n²), which is worse.
list.Sort((a, b) => a.From < b.From ? -1 : a.From > b.From ? 1 : 0);
As an aside, I wrote this solution because you asked for one that is performance-optimised. To this end, I didn’t make it generic, I didn’t use delegates, I didn’t use Linq extension methods, and I used local variables of primitive types and tried to avoid accessing object fields as much as possible.
Here's another one :
IEnumerable<Range> Merge(IEnumerable<Range> input)
{
input = input.OrderBy(r => r.Category).ThenBy(r => r.From).ThenBy(r => r.To).ToArray();
var ignored = new HashSet<Range>();
foreach (Range r1 in input)
{
if (ignored.Contains(r1))
continue;
Range tmp = r1;
foreach (Range r2 in input)
{
if (tmp == r2 || ignored.Contains(r2))
continue;
Range merged;
if (TryMerge(tmp, r2, out merged))
{
tmp = merged;
ignored.Add(r1);
ignored.Add(r2);
}
}
yield return tmp;
}
}
bool TryMerge(Range r1, Range r2, out Range merged)
{
merged = null;
if (r1.Category != r2.Category)
return false;
if (r1.To + 1 < r2.From || r2.To + 1 < r1.From)
return false;
merged = new Range
{
From = Math.Min(r1.From, r2.From),
To = Math.Max(r1.To, r2.To),
Category = r1.Category
};
return true;
}
You could use it directly:
var mergedList = Merge(list);
But that would be very inefficient it you have many items as the complexity is O(n²). However, since only items in the same category can be merged, you can group them by category and merge each group, then flatten the result:
var mergedList = list.GroupBy(r => r.Category)
.Select(g => Merge(g))
.SelectMany(g => g);
Assuming that the list is sorted -and- the ranges are non overlapping, as you have stated in the question, this will run in O(n) time:
var flattenedRanges = new List<Range>{new Range(list.First())};
foreach (var range in list.Skip(1))
{
if (flattenedRanges.Last().To + 1 == range.From && flattenedRanges.Last().Category == range.Category)
flattenedRanges.Last().To = range.To;
else
flattenedRanges.Add(new Range(range));
}
This is assuming you have a copy-constructor for Range
EDIT:
Here's an in-place algorithm:
for (int i = 1; i < list.Count(); i++)
{
if (list[i].From == list[i - 1].To+1 && list[i-1].Category == list[i].Category)
{
list[i - 1].To = list[i].To;
list.RemoveAt(i--);
}
}
EDIT:
Added the category check, and fixed the inplace version.
i have List of int which consists of value 0,0,0,1,2,3,4,0,0 now i like to split this into 3 lists like this list A consists 0,0,0 and List B consists 1,2,3,4 and List C consists 0,0.I know how split using if and for,but how can i do this using linq. usual format i need split in starting some zeros and in middle some values and in last some zeros i need to split this first zeros in one list ,middle values in one list and end zeros in another list as i say in example above here using linq and also i like to take the index that values.
first one.
myList.TakeWhile(x => x==0)
second one.
myList.SkipWhile(x => x==0).TakeWhile(x => x!= 0)
third one.
myList.SkipWhile(x => x==0).SkipWhile(x => x!= 0)
If you want to split by zero sequence then try this code:
static void Main(string[] argv)
{
var list = new[] { 0, 0, 0, 1, 2, 3, 4, 0, 0 };
int groupIndex = 0;
var result = list.Select(
(e, i) =>
{
if (i == 0)
{
return new {val = e, group = groupIndex};
}
else
{
groupIndex =
(e != 0 && list[i - 1] == 0) || (e == 0 && list[i - 1] != 0)
?
groupIndex + 1
: groupIndex;
return new {val = e, group = groupIndex};
}
}
).GroupBy(e => e.group).Select(e => e.Select(o => o.val).ToList()).ToList();
foreach (var item in result)
{
foreach (var val in item)
{
Console.Write(val + ";");
}
Console.WriteLine();
Console.WriteLine("Count:" + item.Count);
Console.WriteLine();
}
Console.ReadLine();
}
Output is:
0;0;0;
Count:3
1;2;3;4;
Count:4
0;0;
Count:2
It is really not clear what is a criteria of split from your question. If I gave wrong answer then explain your question.
You can use the Skip and Take methods exposed by Linq to Objects to grab certain elements of a sequence.
var myList = new int[] {0,0,0,1,2,3,4,0,0};
var list1 = myList.Take(3);
var list2 = myList.Skip(3).Take(4);
var list3 = myList.Skip(7);
You can use Take(n) or Skip(n) in linq
List<int> list = new List<int>();
list.Add(0);
list.Add(0);
list.Add(0);
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(0);
list.Add(0);
var listOne = list.Take(3);
var listSecond = list.Skip(3).Take(4);
var listThird = list.Skip(7);