Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I need a method to return the select elements in a 1D array where the the position of the elements are stored in another array as follow:
double[] A = new double[11] { 8, 9, 8, 7, 5, 6, 4, 8, 9, 6, 5};
Int32[] C = new Int32[3] { 1, 5, 8};
double[] B = MyMethod(A, C);
It should return:
{9, 6, 9}
I'm lost in Linq's Select, Where, Take :-)
With linq, all you would need to do is Select from the Offset array of int and project those int elements into the indexer of the source array
Here is a generic solution that will work with any type
Given
public static T[] SliceAndDice<T>(T[] source, int[] offsets)
=> offsets.Select(t => source[t]).ToArray();
Usage
var a = new double[11] { 8, 9, 8, 7, 5, 6, 4, 8, 9, 6, 5 };
var b = new int[3] { 1, 5, 8 };
var results = SliceAndDice(a,b);
Console.WriteLine(string.Join(", ", results));
Output
9, 6, 9
If you need the brackets
Console.WriteLine($"{{{string.Join(", ", results)}}}");
Output
{9, 6, 9}
For a completely validated and checked extension method
public static T[] SliceAndDice<T>(this T[] source, int[] offsets)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (offsets == null) throw new ArgumentNullException(nameof(offsets));
var result = new T[offsets.Length];
for (var i = 0; i < offsets.Length; i++)
{
if(offsets[i] >= source.Length)
throw new IndexOutOfRangeException("Index outside the bounds of the source array");
result[i] = source[offsets[i]];
}
return result;
}
This is very similar to the other answer, just stripped down to the bare minimum for an extension method.
static class Program
{
static void Main(string[] args)
{
double[] A = new double[] { 8, 9, 8, 7, 5, 6, 4, 8, 9, 6, 5 };
double[] B = A.Slice(new[] { 1, 5, 8 } );
}
public static T[] Slice<T>(this T[] array, IEnumerable<int> index)
{
return index.Select((i) => array[i]).ToArray();
}
}
You can use overload of LINQ Where extension method which uses index:
var x = A.Where((z, index) => C.Any(j => j == index));
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have multiple arrays of objects T -> where T : IComparable<T>.
Each array contains unique elements. An element could be present in multiple arrays but not multiple times in the same array. I need to move all elements that are contains in all arrays to the front of the arrays (in the same order) and get the count of the elements (that are moved so i can have a slice of each array). What would be the most optimal algorithm perf/memory wise?
var a = new[] {4, 5, 6, 7, 8};
var b = new[] {7, 4, 3, 1, 2};
... (up to 8 arrays)
int length = SortAsc(a, b, ...)
// a -> {4, 7, 5, 6, 8}
// b -> {4, 7, 3, 1, 2}
// length = 2
You can use the Intersect method (in System.Linq) to get all the common items. Then you can use Union to join the intersection with the original array. Because we specify intersection.Union(array) instead of array.Union(intersection), the intersection items will appear first in the result. Also, the set operation methods (Union, Intersect, Except) will automatically remove any duplicates:
var a = new[] {4, 5, 6, 7, 8};
var b = new[] {7, 4, 3, 1, 2};
// Common items, ordered by value ascending
var intersection = a.Intersect(b).OrderBy(i => i);
// Union the intersection to put the intersected items first
// (the duplicates are removed automatcially by Union)
a = intersection.Union(a).ToArray();
b = intersection.Union(b).ToArray();
To get the intersection of multiple arrays, it would be handy to add them to a list and then we can use the Aggregate method:
var a = new[] {4, 5, 6, 7, 8};
var b = new[] {7, 4, 3, 1, 2};
var c = new[] {9, 1, 7, 4, 2};
var d = new[] {3, 1, 4, 2, 7};
var e = new[] {3, 7, 4, 1, 2};
var f = new[] {7, 4, 3, 1, 9};
var g = new[] {4, 1, 7, 9, 8};
var h = new[] {3, 2, 6, 7, 4};
var arrays = new List<int[]> {a, b, c, d, e, f, g, h};
var intersection = arrays.Aggregate((accumulation, next) =>
accumulation.Intersect(next).ToArray()).OrderBy(i => i);
Note that this is not the best performing solution, just a simple one to write. :)
Oh, and you can get the count of common items using intersection.Count().
As per I understood, I made an example in a console app:
This is the program.cs
static void Main(string[] args)
{
var a = new int[5] { 4, 5, 6, 7, 8 };
var b = new int[5] { 7, 4, 3, 1, 2 };
var c = new int[5] { 4, 2, 1, 7, 9 };
var d = new int[5] { 1, 2, 6, 4, 5 };
var leng = SortAsc(a, b, c, d);
if (leng.Arrays.Count > 0)
{
Console.WriteLine($"Length: {leng.Arrays.Count}");
foreach (var item in leng.Arrays)
{
for (int i = 0; i < item.Length; i++)
{
Console.Write($"{item[i]}");
}
Console.WriteLine();
}
}
}
This is the method:
public static ArrayKeeper SortAsc(int[] a, int[] b, int[] c, int[] d)
{
//order arrays
a = a.OrderBy(o => o).ToArray();
b = b.OrderBy(o => o).ToArray();
c = c.OrderBy(o => o).ToArray();
d = d.OrderBy(o => o).ToArray();
a = a.OrderByDescending(o => b.Contains(o)).ToArray();
b = b.OrderByDescending(o => a.Contains(o)).ToArray();
c = c.OrderByDescending(o => (a.Contains(o) && b.Contains(o))).ToArray();
d = d.OrderByDescending(o => (a.Contains(o) && b.Contains(o)) && c.Contains(o)).ToArray();
var resp = new ArrayKeeper();
resp.Arrays.Add(b);
resp.Arrays.Add(a);
resp.Arrays.Add(c);
resp.Arrays.Add(d);
return resp;
}
This is a DTO to help transport data;
public class ArrayKeeper {
public ArrayKeeper()
{
Arrays = new List<int[]>();
}
public List<int[]> Arrays { get; set; }
}
This is the result:
$ dotnet run
Length: 4
47123
47568
47129
41256
Of course it's a POC and is just one way to do something like you want using LINQ, Lists and arrays;
Also I think it will need some kind of validation to be more dynamic;
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have list
List<int> listnumbers
with values { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }.
In some cases i need to add new value for existing values in list example , 0 => 5, 1 => 6 ....
Is there way to do that?
EDIT
i want number to
number 0 have stake 5
number 1 have stake 6
But i cannot that declare on begining of program , only in some cases i woud join stakes
EDIT 2
I will use multidimensional array so it will be
0=>5
1=>6
array[0][0] = 0;
array[0][1] = 5;
array[1][0] = 1;
array[1][1] = 6;
Perhaps this could do what you're looking for. You need some kind of data structure to store the additional information:
public class NumberLink {
int Value { get; set; }
int Link { get; set; }
}
List<NumberLink> numberLinks =
new List<int> {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
}
.Select(i => new NumberLink { Value = i })
.ToList();
numberLinks.First(nl => nl.Value == 0).Link = 5;
numberLinks.First(nl => nl.Value == 1).Link = 6
Please note that if you will always have a range of numbers from 0..n, you don't need this. You can simply use the position of the item in the list to represent the first value, such that a list { 5, 6 } indicates that 0 goes to 5 and 1 goes to 6.
If you need to substitute a value for another, you could use Linq, something along the lines of:
List<int> list = new List<int>(){0,1,2,3,4,5,6};
var fromValue = 0;
var toValue = 7;
list = list.Select( x => x = (x == fromValue ? toValue : x)).ToList();
//- list = {7,1,2,3,4,5,6}
Here the Select statement will mutate your existing list and return a modified list of integers where every value that's equal to fromValue will be replaced with toValue
CASE 1. To add them at the end of the list:
listnumbers.Add(5);
listnumbers.Add(6);
list will be listnumbers ==> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 6 }
CASE 2. To insert them at a specific position:
listnumbers.Insert(0, 5);
listnumbers.Insert(0, 6);
list will be listnumbers ==> { 6, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
CASE 3. To insert them at position that maintains an ordered list (min to max):
listnumbers.Insert(listnumbers.FindIndex(0, x => x == 5) + 1, 5);
listnumbers.Insert(listnumbers.FindIndex(0, x => x == 6) + 1, 6);
list will be listnumbers ==> { 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12 } and in this case, I am using predicates within FindIndex method.
I am guessing that you want to add some constant value to each element of a list and return it as a new list.
List<int> answer = listnumbers.Select(x => x+valueToBeAdded).ToList();
The above statement adds a constant to all elements of the list and returns it as a new list.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Consider I've an array of integers {1,2,3,4,5,6,7,8} and I want to pair them up as {{1,2},{3,4} and so on} and perform subtraction on the pair and finally sum the results.
Following is the code I've now and for better understanding:
static void Main(string[] args)
{
int[] ints = { 4, 8, 8, 3, 9, 0, 7, 8, 2, 2 };
ints = ints.OrderBy(x => x).Select(x=>x).ToArray();
List<int> lints = new List<int>();
for (int i = 0, j = 1; i < ints.Length; i = i + 2, j = j + 2)
{
lints.Add(ints.ElementAtOrDefault(j) - ints.ElementAtOrDefault(i));
}
int lintsum = lints.Sum();
Console.WriteLine(lintsum);
}
Is there a better way to do this in linq in C#? And how can I do the same in python?
You can use MoreLINQ which has a Pairwise extension method on IEnumerable<T> which does exactly what you want, it invokes a delegate on an element and its predecessor:
var ints = new[] { 1, 2, 3, 4, 5 };
var result = ints.Pairwise((first, second) => second - first);
Console.WriteLine(result.Sum());
You could achieve the result using Python in the following way:
In [25]: start = [1,2,3,4,5,6,7,8]
In [26]: tuples = [item for item in zip(start[::2], start[1::2])]
In [27]: tuples
Out[27]: [(1, 2), (3, 4), (5, 6), (7, 8)]
In [28]: answer = sum(rhs-lhs for (lhs, rhs) in tuples)
In [29]: answer
Out[29]: 4
An alternative solution using Python is:
ints = [1, 2, 3, 4, 5, 6, 7, 8]
print sum(y - x for x, y in zip(*([iter(ints)] * 2)))
ints = [4, 8, 8, 3, 9, 0, 7, 8, 2, 2]
print sum(y - x for x, y in zip(*([iter(ints)] * 2)))
Giving:
4
-9
When using large arrays of number, it might be preferable to use numpy:
import numpy as np
ints = np.array([1, 2, 3, 4, 5, 6, 7, 8])
tuples = ints.reshape(-1,2))
Then take the difference and sum
(tuples[:,1]-tuples[:,0]).sum()
Or alternatively
np.diff(tuples).sum()
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) } );