- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个类 Product
来保存给定产品的特定实例。这个类有一个与主产品相似的相关产品列表。
class Product
{
public string Name;
public double Rating;
public List<Product> RelatedProducts;
//...
public List<Product> GetTopRelatedProducts(int N)
{
// How to implement this method
// What I did so far(Bad code)
// 1- INFINITE RECURSION
// 2- Can not remember visited objects
var myList = new List<Product>();
foreach(Product prod in RelatedProducts)
{
myList.AddRange(prod.GetTopRelatedProducts(N));
}
return myList.Distinct().OrderByDescending(x => x.Rating).Take(N).ToList();
}
}
我想在 Product
类中定义一个方法来获取顶级 N
(评分最高)的相关产品。此方法应考虑到 RelatedProducts
列表中的元素属于 Product
类型,并且它们也有自己的 RelatedProducts
列表。所以我应该继续导航嵌套对象,直到到达所有相关产品,然后再获取前 N 个产品。我的意思是,解决方案不会只是 this.RelatedProducts.OrderByDescending(x => x.Rating).Take(N);
还有一点要记住:两个产品可以相互关联。这意味着产品 A 可以属于 RelatedProducts
产品列表 B 和 B 也可以属于 RelatedProducts
产品列表A。
关于如何以最佳方式解决这个问题有什么建议吗?
想象一下,我有数百万个产品需要维护。我如何递归地导航所有相关产品并识别已经访问过的产品?
我将其标记为 C# 和 Java,因为相同的逻辑可以应用于两种语言
最佳答案
Imagine, I have millions of products to maintain. How can I navigate all related products recursively and recognize already visited ones?
它不需要是递归的。显式 Stack
或 Queue
可以服务于导航部分。为了收集结果,可以使用 HashSet
代替 List
。它有两个用途 - 允许您跳过已经访问过的元素,并且还消除了最后对 Distinct
的需要。
下面是一个基于 Queue
的实现示例:
public List<Product> GetTopRelatedProducts(int N)
{
var relatedSet = new HashSet<Product>();
var relatedListQueue = new Queue<List<Product>>();
if (RelatedProducts != null && RelatedProducts.Count > 0)
relatedListQueue.Enqueue(RelatedProducts);
while (relatedListQueue.Count > 0)
{
var relatedList = relatedListQueue.Dequeue();
foreach (var product in relatedList)
{
if (product != this && relatedSet.Add(product) && product.RelatedProducts != null && product.RelatedProducts.Count > 0)
relatedListQueue.Enqueue(product.RelatedProducts);
}
}
return relatedSet.OrderByDescending(x => x.Rating).Take(N).ToList();
}
更新:为了完整起见,这里是相关集收集部分的其他可能实现:
使用显式堆栈
:
public List<Product> GetTopRelatedProducts(int N)
{
if (RelatedProducts == null || RelatedProducts.Count == 0)
return new List<Product>();
var relatedSet = new HashSet<Product>();
var pendingStack = new Stack<List<Product>.Enumerator>();
var relatedList = RelatedProducts.GetEnumerator();
while (true)
{
while (relatedList.MoveNext())
{
var product = relatedList.Current;
if (product != this && relatedSet.Add(product) && product.RelatedProducts != null && product.RelatedProducts.Count > 0)
{
pendingStack.Push(relatedList);
relatedList = product.RelatedProducts.GetEnumerator();
}
}
if (pendingStack.Count == 0) break;
relatedList = pendingStack.Pop();
}
return relatedSet.OrderByDescending(x => x.Rating).Take(N).ToList();
}
虽然比显式基于Queue
的实现更冗长,但此方法对空间的要求更小 - O(height) 其中 height
是最大深度。
这两种迭代实现的好处当然是它们可以处理比递归解决方案更大的深度,递归解决方案可能导致 StackOverflowExpection
。但是如果深度不期望这么大并且你更喜欢递归,那么这里有几个递归实现(他们需要访问 relatedSet
和 this
) :
使用经典的私有(private)递归方法:
public List<Product> GetTopRelatedProducts(int N)
{
var relatedSet = new HashSet<Product>();
GetRelatedProducts(this, relatedSet);
return relatedSet.OrderByDescending(x => x.Rating).Take(N).ToList();
}
private void GetRelatedProducts(Product product, HashSet<Product> relatedSet)
{
if (product.RelatedProducts == null) return;
foreach (var item in product.RelatedProducts)
if (item != this && relatedSet.Add(item))
GetRelatedProducts(item, relatedSet);
}
使用递归 lambda:
public List<Product> GetTopRelatedProductsD(int N)
{
var relatedSet = new HashSet<Product>();
Action<Product> GetRelatedProducts = null;
GetRelatedProducts = product =>
{
if (product.RelatedProducts == null) return;
foreach (var item in product.RelatedProducts)
if (item != this && relatedSet.Add(item))
GetRelatedProducts(item);
};
GetRelatedProducts(this);
return relatedSet.OrderByDescending(x => x.Rating).Take(N).ToList();
}
最后但同样重要的是,最新的 C# 7.0 添加 - 递归 local function :
public List<Product> GetTopRelatedProducts(int N)
{
var relatedSet = new HashSet<Product>();
GetRelatedProducts(this);
return relatedSet.OrderByDescending(x => x.Rating).Take(N).ToList();
void GetRelatedProducts(Product product)
{
if (product.RelatedProducts == null) return;
foreach (var item in product.RelatedProducts)
if (item != this && relatedSet.Add(item))
GetRelatedProducts(item);
}
}
所有这些方法都以最佳方式处理 (IMO) 收集部分。前 N 部分当然不是最优的 - O(N*log(N)) 并且可以按照@Amit Kumar 的回答中提到的那样进行优化,但它需要实现一个缺失的标准数据结构,这超出了 SO 答案的范围。
关于java - 选取相关对象的前N个元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43048526/
第一段代码工作正常,并给出了我需要的结果。我现在想做的是让它在 'as num' 上返回 3 个数字值对于“as num”上的 3 个不同值,对于同一列上的 3 个不同位置 SELEC
我想分析一些数据以编写定价算法。以下日期可用: 我需要三个变量/维度的函数/相关因子,它显示三个维度(pers_capacity、卧室数量、浴室数量)增长时中位数(价格)的变化。例如Y(#pers_c
正如标题所说 - 我的 Sprite Kit 游戏时不时地在后台崩溃,总是出现此错误 - Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Sub
假设我尝试保存以下数据,并且Songs模型的name属性上设置了Phalcon \ Mvc \ Model \ Validator \ PresenceOf验证器 // Get an existing
我有一个 if 控件,如下所示; if (Directory.Exists(System.IO.Path.Combine(systemPath, "Reports", companyName))
有人可以告诉我我们使用 ReadLine() 从文件 (.txt) 中读取特定行吗?现在我想读取文件的全部内容(不仅仅是第一行)。为此我需要使用什么方法。我用谷歌搜索了很多,但找不到解决方案。 我的代
我相信在大学时我用从 C 派生的语言为 FPGA 编写了一个程序。我了解 VHDL 和 verilog 等语言。但是,我不明白的是程序员在使用哪个方面有多少选择?它依赖于FPGA吗?我将使用 Xili
我有一个 if 控件,如下所示; if (Directory.Exists(System.IO.Path.Combine(systemPath, "Reports", companyName))
如何在运行时更改 Dashcode (Javascript) 中图像对象的源? 我试过: var image = document.getElementById("image").object;ima
我有几个相互关联的类,它们将被多种不同的算法使用 例子: struct B; struct A { B* parent; }; struct B { std::vector child
我正在开发一个网站,用户在客户收到的表中输入金额,如果任何客户没有提供分期付款(金额),则用户不会在表中输入任何金额,并且用户希望获取违约者的信息客户以10天为基础。所以我的问题是应该定义什么表和属性
我试图从上一个条目中选择一个值,并每次将该数字加一。我让它工作到选择当前条目值(默认 1000)并递增 1 并重新插入该值(因此每次最终都是 1001)。我需要它来选择该字段的最后一个条目,这样它将变
我不擅长“制作”查询。假设这是我的数据库: artist pics ------------------- -
最近,我要为我的网站做一个即时通知系统。我听说 COMET 在这种情况下必不可少。 我已经搜索 PHP 和 Comet 一段时间了,但是,我发现的指南和文章似乎只是循环中的 ajax 请求。例如,有一
我正在开发一款 iOS 游戏,我希望 clown 在场景外生成,然后向下移动。我的想法是全部创建它们,并将它们以 360 像素的距离放置在不可见的场景中。 像这样: SKSpriteNode *clo
我有以下子订单表。 mysql> select * from suborder; +-------------+------------------+ | order_state | bookin
这可能是一个有点初学者的问题,但考虑到在 Java 中调试编码是相当相关的:什么时候编码与 String 对象相关? 假设我有一个要保存到文件中的字符串对象。 String 对象本身是否使用某种我应该
首先我想说我是 CPP 的新手(我从 cpp11 开始):)考虑以下实体:学生(名字+姓氏)和组(描述+更多学生)。我在 C++ 中创建了以下 2 个类: class Student { privat
我正在尝试在单击该复选框时同步更新我的数据库。我决定使用 aJax,但它似乎无法识别 ajax。 代码:将成为 Switch_Active(this.id) 函数的元素 ... Deactivat
我正在创建一个菜单。菜单如下。 $('.category').mouseover(function() { $(this).removeClass('category').addClass('cate
我是一名优秀的程序员,十分优秀!