2016-12-22 1 views
3

주어진 수의 하위 목록에 목록을 균등하게 분배하려고합니다. 예를 들어, 1 ~ 10의 요소 목록이 있고 3 개의 목록이 필요합니다. 이들은 보일 것 같은 :목록을 Java의 하위 목록에 균등하게 배포하십시오.

SL1 -> {1, 2, 3, 4} 
SL2 -> {5, 6, 7} 
SL3 -> {8, 9, 10} 

중요 : 무엇 각 목록에 포함 된 것은 관련이없는, 즉 SL1가 가질 수 {1, 5, 7, 10}. 가장 중요한 것은 크기가 3 인 목록 2 개와 크기 4 인 목록 1 개가 있다는 것입니다.

나는 Iterables.partition을 포함하여 여러 가지를 시도했지만 도움이되지 않습니다.

내가 그 작품을 마련했습니다있는 유일한 방법은 다음과 같습니다

public Iterable<List<Integer>> distributeEvenlyQueryListIntoLists(final LinkedList<Integer> bigList, final Integer numberOfSublists) { 
    List<List<Integer>> result = new ArrayList<>(); 

    // Creates as many lists as needed 
    for (int i = 0; i < numberOfSublists; i++) { 
     result.add(new ArrayList<>()); 
    } 

    while (bigList.iterator().hasNext()) { 
     for (int i = 0; i < numberOfSublists; i++) { 
      if (!bigList.iterator().hasNext()) { 
       break; 
      } 
      result.get(i).add(bigList.poll()); 
     } 
    } 
    return result; 
} 

건네 bigList이 어떤 Iterable 할 수있다하는 LinkedList 일 필요는 없습니다.

특히 하위 목록을 만드는 첫 번째 루프가 싫습니다.

감사합니다.

답변

5

그냥 라운드 로빈 패턴으로 배포 :

public <T> List<List<T>> partition(Iterable<T> iterable, int partitions){ 
    List<List<T>> result = new ArrayList<>(partitions); 
    for(int i = 0; i < partitions; i++) 
     result.add(new ArrayList<>()); 

    Iterator<T> iterator = iterable.iterator() 
    for(int i = 0; iterator.hasNext(); i++) 
     result.get(i % partitions).add(iterator.next()); 

    return result; 
} 

이 코드 샘플 실행 :

List<String> l = Stream.iterate(0, i->i + 1).limit(25).map(i->Integer.toString(i)).collect(Collectors.toList()); 
System.out.println(partition(l, 4).toString()); 

가 생산

[[0, 4, 8, 12, 16, 20, 24], [1,5,9,13,17,21], [2,6,10,14,18,22], [3,7,11,15,19,23] ]

기본적인 아이디어는 결과 집합의 각 목록에 단일 요소를 추가하는 것입니다. 이 방법을 사용하면 두 목록 간의 요소 수 차이가 1을 초과하지 않습니다.

guavas 구현을 Iterables.partition으로 사용할 수 있습니다. 약간 다른 접근 방식을 취할 수 있습니다.

+0

대단한 분께 고마워요! 어떤 방식 으로든 첫 번째 루프를 제거 할 수 있습니까? 그것은 실제로 원래의 솔루션에서 가장 귀찮게하는 것이 었습니다. – user3083022

+0

@ user3083022 정말 아닙니다. 다르게 보이게하기 위해 약간의 마술을 사용할 수 있지만, 결국에는 모든 목록 인스턴스를 생성하는 데 항상 어려움을 겪을 것입니다. – Paul

+0

무슨 마법을 말하는거야?외부 라이너 일지라도 받아 들일 수 있습니다. – user3083022

2

하위 목록 만들기가 싫다면 빠른 해결책을 찾고 있음을 의미합니다. 원본이 List이고 원본을 변경하지 않으려는 경우 List, List.subList()을 고려하십시오.

int subSize = bigList.length()/numSubs; 
int numBigSubs = 0; // # of subs that need to be one bigger 
if (bigList.length() % numSubs > 0) { 
    subSize++; 
    numBigSubs = bigList.length() % numSubs; 
} 
int from = 0; 
int to = subSize; 
List<List<Integer>> subList = new ArrayList<List<Integer>>(numSubs); 
for (int i = 0; i < numSubs; i++) { 
    List<Integer> newSub = bigList.subList(from, to); 
    subList.add (newSub); 
    from = to; 
    to += subSize; 
    if (i >= numBigSubs && numBigSubs > 0) to--; 
} 

참고 : 나는 시험없이 쓴 - 실패하면, 내가 사과, 누군가가이 일을 편집 바랍니다.

다시 말해서, 위의 큰 장점은 빠르게 악의적 인 것이어야한다는 것입니다. 모든 하위 목록은 단순히 큰보기로 보는 것입니다. 단점은 목록을 변경하면 모든 배팅이 해제된다는 것입니다.

+0

이 코드는 예상대로 작동하지 않습니다. 'input-list % numSubs = 3'이라고 가정하십시오. 여러분의 코드는'subSize' 엘리먼트로'numSubs - 1'리스트를 만들고'subSize - 3' 엘리먼트로 하나의리스트를 생성 할 것입니다. – Paul

+0

나는 이것을 처리하기위한 코드를 편집하고 있었기 때문에 걱정을 덜어주었습니다. 이제'big.length() == 15 && numSubs == 4'라고하면,'subSize'는 이제'big.length()/numSubs + 1 == 4'로 설정됩니다. 그러면 이제 하위 목록을 가져와야합니다. 0-4, 4-8, 8-12, 12-15가되어야합니다. 어떻게 생각해? –

+0

(OP는 완벽하게 지정하지는 않았지만 언급 한대로 라운드 로빈이 필요하다고 생각합니다. 즉, 모든 하위 목록 길이는 1보다 길어야하며, 필요한 경우 가장 큰 하위 목록이 더 큰 것입니다.) –

관련 문제