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是一個序列,它將序列合並為一個序列
=====2020=====
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; }