最近做的项目(自己练练手的那种)遇到了一个很有趣的问题,比如这样一个字符串,http://www.example.com/{field1}/{field2}/{field3},当然这里的field个数是不确定的,但是每一个field都知道其范围,要实现的功能就是把所有的url计算出来。
如果field的个数确定,你大可放心地用for循环,不断地嵌套就可以实现,但是这里是不确定的,我想到的方案是使用Stack,用Stack来模拟嵌套的for循环。
首先为field建个模型,说白了就是写了class表示它:
public class RangeItem
{
private int position = 0;
/// <summary>
/// 对应的field位置
/// </summary>
public int Position
{
get { return position; }
set { position = value; }
}
private int rangeMin = 0;
/// <summary>
/// 范围最小值
/// </summary>
public int RangeMin
{
get { return rangeMin; }
set { rangeMin = value; }
}
private int rangeMax = 0;
/// <summary>
/// 范围最大值
/// </summary>
public int RangeMax
{
get { return rangeMax; }
set { rangeMax = value; }
}
private int currentIndex = -1;
/// <summary>
/// 在Range中的位置,这个属性用于在循环中保存当前的处理序号,因为我们在用Stack模拟嵌套的for循环
/// </summary>
public int CurrentIndex
{
get { return currentIndex == -1 ? rangeMin : currentIndex; }
set { currentIndex = value; }
}
}
然后呢再封装一下,把所有的RangeItem集中管理
public class RangeItemManager
{
private static List<RangeItem> rangeItems = new List<RangeItem>();
/// <summary>
/// 所有的RangeItem
/// </summary>
public static List<RangeItem> Items
{
get { return RangeItemManager.rangeItems; }
set { RangeItemManager.rangeItems = value; }
}
}
核心的代码如下
if (RangeItemManager.Items.Count == 0)
return null;
RangeItemManager.Items.Sort(Compare);
RangeItem firstItem = RangeItemManager.Items[0];
//如果只有一个field,则简单地通过一个for处理
if (RangeItemManager.Items.Count == 1) {
for (int i = firstItem.RangeMin; i <= firstItem.RangeMax; i++)
Action(i);
} else {
//循环最外层的,对应field1
for (int i = firstItem.RangeMin; i <= firstItem.RangeMax; i++) {
stack = new Stack<int>();
//把最外层的那个值入栈
stack.Push(i);
//循环剩余的RangeItem
ProcessInnerLoop(0);
}
}
public static int Compare(RangeItem x, RangeItem y)
{
return x.Position > y.Position ? 0 : 1;
}
private static void ProcessInnerLoop(int current)
{
++current;
//如果是最里层(fieldmax),则直接进行遍历
if (current == RangeItemManager.Items.Count - 1) {
RangeItem item = RangeItemManager.Items[current];
for (int i = item.RangeMin; i <= item.RangeMax; i++) {
//获取全部入栈的元素,这样算是完成了一次处理,可以产生了一个url
List<int> lst = stack.ToList();
lst.Reverse();
lst.Add(i);
Action(lst);
}
} else {
RangeItem item = RangeItemManager.Items[current];
for (int i = item.CurrentIndex; i <= item.RangeMax; i++) {
//把当前值入栈
stack.Push(i);
//处理下一个RangeItem.
ProcessInnerLoop(current);
//修改当前RangeItem的CurrentIndex,下一次循环是从CurrentIndex开始的
item.CurrentIndex = i + 1;
if (item.CurrentIndex >= item.RangeMax)
item.CurrentIndex = item.RangeMin;
//把当前值出栈
stack.Pop();
}
}
}
private static void Action(List<int> lst)
{
object[] objs = new object[lst.Count];
for (int i = 0; i < lst.Count; i++) {
objs[i] = (object)lst[i];
}
string url = String.Format(UrlFormator, objs);
//TargetUrls.Urls是一个List<string>
TargetUrls.Urls.Add(url);
}
private static void Action(int i)
{
string url = String.Format(UrlFormator, i);
//TargetUrls.Urls是一个List<string>
TargetUrls.Urls.Add(url);
}
贴了这么一大段代码,给我的感觉就是啰嗦,效率也是个问题,尤其是在field很多、每个RangeItem范围很广的时候,写这篇post的目的就是大家一起讨论,看看有没有更好的实现方式,谢谢。
posted @ 2010-05-26 21:50 dongzz 阅读(98) 评论(0) 编辑
如果你经常学习新技术,那不可避免会写很多demo,时间一长你VS文件菜单下的"Recent Projects"肯定乱作一团,就像我的这样:

清理的办法也很简单,最直接的方法就是使用最下面的"Clear Recent Project List",但是如果你想调整一下两个Item的顺序,我提供的这个工具就可以帮上忙了。

使用方法很简单,选择你当前的VS版本,点一下"load"按钮,然后通过右边的按钮进行调整、删除,完成后点"save"就行了,重启IDE生效。
最后附上下载地址 Download,由于个人水平有限,难免有bug,希望大家在评论中指出。
posted @ 2010-05-26 17:21 dongzz 阅读(37) 评论(0) 编辑
