C#獲取數組/字符串的k個字符的全部組合


   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;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM