对多个数组进行排序和切片[关闭]
Posted
技术标签:
【中文标题】对多个数组进行排序和切片[关闭]【英文标题】:Sort and slice multiple arrays [closed] 【发布时间】:2021-02-06 21:10:34 【问题描述】:我有多个对象数组T -> where T : IComparable<T>
。
每个数组都包含唯一的元素。一个元素可以出现在多个数组中,但不能多次出现在同一个数组中。我需要将所有数组中包含的所有元素移动到数组的前面(以相同的顺序)并获取元素的计数(移动这些元素以便我可以拥有每个数组的切片)。在性能/内存方面最佳的算法是什么?
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
【问题讨论】:
除了@RufusL 建议的内容之外,还请澄清您不知道如何实施的部分 - 例如,有很多问题显示如何找到“元素存在于所有数组中”或“移动数组中的元素”......而且“切片”通常假设大块 - 听起来像 1, 2,3,5 + 6, 2,4,5 应该产生 2,5,1,3 + 2,5, 6,4 这听起来不像“切片”,而是移动到我这里 @RufusL 我希望这很清楚。 @AlexeiLevenkov 我正在寻找最好的算法,而不是为了实现 @ptp 完全不清楚 - "4,7" 与t[7, 4, 3, 1, 2]
的“顺序相同”如何?
您说“相同的顺序”,但没有定义该顺序是什么。您只是按价值升序对它们进行排序吗?还是按照它们在一个特定数组中出现的顺序?
【参考方案1】:
您可以使用Intersect
方法(在System.Linq
中)获取所有常用项。然后您可以使用Union
加入与原始数组的交集。因为我们指定intersection.Union(array)
而不是array.Union(intersection)
,所以intersection
项将首先出现在结果中。另外,set 操作方法(Union
、Intersect
、Except
)会自动删除所有重复项:
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();
要获取多个数组的交集,可以方便地将它们添加到列表中,然后我们可以使用Aggregate
方法:
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);
请注意,这不是性能最好的解决方案,只是一个简单的解决方案。 :)
哦,您可以使用intersection.Count()
获取常见项目的数量。
【讨论】:
不错。 “最佳 ... 内存”请求完全失败,因为它是 O(总数组大小)与 O(1)的内存优化解决方案......但我强烈怀疑 OP 添加内存优化要求只是为了......让人们感到困惑试图回答。 @AlexeiLevenkov 哦,废话。我真的需要学习阅读。 只是为了澄清我的评论 - 当单一算法可以同时优化时间和内存时,这是非常罕见的。在这种特殊情况下,由于 O(total_number_items ^ 2) 时间复杂度,明显的 O(1) 内存使用解决方案(逐个检查所有数组中的每个项目)听起来并不实用。也有可能加快一些仍在原地的检查,但代码会涉及更多(因为没有原地/没有内存使用 LINQ 帮助器)。【参考方案2】:据我了解,我在控制台应用程序中做了一个示例:
这是程序.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();
这是方法:
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;
这是一个帮助传输数据的 DTO;
public class ArrayKeeper
public ArrayKeeper()
Arrays = new List<int[]>();
public List<int[]> Arrays get; set;
这是结果:
$ dotnet run
Length: 4
47123
47568
47129
41256
当然,它是一个 POC,它只是使用 LINQ、列表和数组来做你想做的事情的一种方式;
另外我认为它需要某种验证才能更加动态;
【讨论】:
这似乎移动了在所有数组中不常见的项目,如果7
存在,则将其放在第二位,然后对剩余的项目进行排序。以上是关于对多个数组进行排序和切片[关闭]的主要内容,如果未能解决你的问题,请参考以下文章