static IEnumerable<string> foo(string metachars, int i)
{
var query = metachars.Select(x => x.ToString().AsEnumerable());
while (query.First().Count() < i)
{
var ee = query.First();
//是原始的
//query = query.SelectMany(x => metachars.Where(y => y > x.Last()).Select(y => x.Concat(y.ToString().AsEnumerable())));
query = query.SelectMany(x => metachars.Where((y, y_index) => y_index > metachars.IndexOf(x.Last())).Select(y => x.Concat(y.ToString().AsEnumerable())));
//无论哪种写法,都无法应用于内部含有重复字符串,因为对于上方的,char相同,会忽略掉重复的那个;下方那个返回第一个index,会出现重复
}
return query.Select(x => string.Join(",", x));
}
foreach (var item in foo("bacdef", 4))//使用
{
Console.WriteLine(item);
}
第一行按照char大小来排的是网络大神写的
第二行按照索引是我改进的另一种写法
对于为什么要加AsEnumerable(),是因为只有可遍历的迭代器,才可以使用Concat方法
上方公式的原理就是:
首先第一次,query可迭代的每个里面只含有一个字符,无论取First()还是第二、第三个,他们的容量count都是1
然后向后找,就是我们基本for循环来做的思想,一个个向后,如:abcd这样我们就是ab ac ad bc bd cd 这样一个个固定前方索引,向后找。此次count都是2
若输入为"abcd",3的话
第一次循环后query变为:ab ac ad bc bd cd
第二次过程则为:ab,因为b的索引为1,依次找比b大的,则abc abd, 对于ac ad..也是这样,对于cd,找比d大的没有,则就找不到啦
他的整个思想为,我要取数组的k个值的全部组合,那么我一点点从取一个开始(当然就是本身),然后所有取2个的组合,然后在2个的基础上取所有3个的组合,以此类推,直到k个!
对于数组也是一样,只需要在Last()后加.ToString(),对于int类型数组,也是只需要将Last()后转为int类型即可
static IEnumerable<string> foo2(List<string> metachars, int i)
{
var query = metachars.Select(x => x.ToString().AsEnumerable());
while (query.First().Count() < i)
{
var ee = query.First();
//是原始的
//query = query.SelectMany(x => metachars.Where(y => y > x.Last()).Select(y => x.Concat(y.ToString().AsEnumerable())));
query = query.SelectMany(x => metachars.Where((y, y_index) => y_index > metachars.IndexOf(x.Last().ToString())).Select(y => x.Concat(y.ToString().AsEnumerable())));
//无论哪种写法,都无法应用于内部含有重复字符串,因为对于上方的,char相同,会忽略掉重复的那个;下方那个返回第一个index,会出现重复
}
return query.Select(x => string.Join(",", x));
}
List<string> list2 = new List<string>() { "a","b","c","d","e","f"};//使用
foreach (var item in foo2(list2, 3))
{
Console.WriteLine(item);
}
如果想要int的话,就先使用string,然后再转成int
使用List
public static List<string> getAllCombination(int k, List<int> list)
{
var query = list.Select(x => x.ToString().AsEnumerable());
while (query.First().Count() < k)
{
query = query.SelectMany(x => list.Where((y, y_index) => y_index >list.FindIndex(z=>z==int.Parse(x.Last().ToString()))).Select(y=>x.Concat(y.ToString())));
}
return query.Select(x => string.Join(",", x)).ToList();
}
以上的代码,看似没啥问题,但是当我数组中含有2位以上的数的时候,那就完蛋了,全乱套了,为了解决这个问题,我研究出如下方法!
通用非重复数组取数字方法!!!!By 程序杰杰
//适用于所有的非重复的数组方法!!!
//由博主本人研究写出,如需引用必须注明博主网址哦
public static List<List<int>> getAllCombinationCeshi2(int k, List<int> list)
{
List<List<int>> list1 = new List<List<int>>();//用来记录,选取k个元素的全部组合
list.ForEach(x => { list1.Add(new List<int>() { x }); });
List<string> listCopy = new List<string>();
list.ForEach(x=> listCopy.Add(x.ToString()));
while (list1[0].Count < k)
{
List<List<int>> list2 = new List<List<int>>();
//select内部只能是一个个的,将这些组合成一个序列
//selectMany内部必须要是可迭代的序列,将序列合并
//选择比当前索引大的全部组合
listCopy = listCopy.SelectMany((x,x_index)=> list.Where((y, y_index) => y_index > list.FindIndex(z => z == list1[x_index][list1[x_index].Count-1])).Select(y=> x+","+y)).ToList();
//更新list1
foreach (var item in listCopy)
{
list2.Add(new List<int>());//此时一定是最后的一个list,因为是新加的嘛
string[] strs=item.Split(',');
foreach (var item1 in strs)
{
list2[list2.Count - 1].Add(int.Parse(item1));
}
}
list1 = list2;
}
return list1;
}
Select与SelectMany
//测试
List<int> listCeshi = new List<int>() { 10,2,30,4,5};
IEnumerable<int> ceshi01 = listCeshi.Select(x=>x);//select内部lambda是一个个的值,将这些值合并为一个新的序列
IEnumerable<int> ceshi02 = listCeshi.SelectMany(x => listCeshi.Select(y => y));//selectMany内部lambda是一个序列,它将序列合并为一个序列
java实现
//随机取字符串k个的全部排列(目前写字符无重复)
public class RandomFetchChar {
public static void main(String[] args) {
//System.out.println("abv".substring(3,3));
System.out.println(getAllPermutation("abc",4));
}
static String front="";
static String rear="";
static ArrayList<String> temp=null;
public static ArrayList<String> getAllPermutation(String str, int k){
if(str.length()<k){
System.out.println("输入有误");
return null;
}
ArrayList<String> res=new ArrayList<String>();
if(k==1){
for (int i = 0; i < str.length(); i++) {
res.add(""+str.charAt(i));
}
}else {
for (int i = 0; i < str.length(); i++) {
front=str.substring(0,i);
rear=str.substring(i+1,str.length());
temp=getAllPermutation(front+rear,k-1);
for (int j = 0; j < temp.size(); j++) {
temp.set(j,str.charAt(i)+temp.get(j));
}
res.addAll(temp);
}
}
return res;
}
}
//泛型数组实现
private <T> LinkedList<LinkedList<T>> getKCombine(T arr[],int k){
LinkedList<T> linkedList=new LinkedList<>();
for (int i = 0; i < arr.length; i++) {
linkedList.add(arr[i]);
}
LinkedList<LinkedList<T>> assistList=new LinkedList<>();
LinkedList<LinkedList<T>> res=getAllCombine(linkedList,arr.length,k,assistList);
return res;
}
private <T> LinkedList<LinkedList<T>> getAllCombine(LinkedList<T> linkedList,int len,int k,LinkedList<LinkedList<T>> assistList){
if(len<k){
throw new RuntimeException("k值输入过大");
}
LinkedList<LinkedList<T>> res=new LinkedList<>();
LinkedList<T> temp;
if(k==1){
for (int i = 0; i < linkedList.size(); i++) {
temp=new LinkedList<>();
temp.add(linkedList.get(i));
res.add(temp);
}
return res;
}
for (int i = 0; i < linkedList.size(); i++) {
T first=linkedList.get(i);
linkedList.remove(i);//移除
assistList=getAllCombine(linkedList,len-1,k-1,assistList);
linkedList.add(i,first);//执行完再加回来
for(LinkedList<T> item:assistList){
item.addFirst(first);
}
res.addAll(assistList);
}
return res;
}