简体   繁体   English

按组对列表进行排序的效率如何?

[英]How efficiently sort a list by groups?

I need to group a given sort list by some given "blocks" or "groups" of elements.我需要按一些给定的“块”或“组”元素对给定的排序列表进行分组。 For example:例如:

Given a list:给出一个列表:

[A, B, C, D, E, F, G, H, I, J]

And groups和团体

[A, C, D]
[F, E]
[J, H, I]

the result should be结果应该是

[A, C, D, B, F, E, G, J, H, I]

The blocks of elements can not be mixed with non-group elements.元素块不能与非组元素混合。 The blocks should have the same order.块应该具有相同的顺序。 The other elements of the list should mantain their order.列表的其他元素应该保持它们的顺序。


I have already found a solution.我已经找到了解决方案。 But it's not the most efficient code as you will see.但这并不是您将看到的最有效的代码。

I'm using java 6 also...我也在使用 java 6 ......

public static List<CategoryProduct> sortProductsByBlocks(List<CategoryProduct> products, CategoryBlocks categoryBlocks) {
    if (!validateCategoryBlocks(categoryBlocks)) {
        return products;
    }
    Map<String, BlockView> mapProductByBlock = mapBlocksByPartnumber(categoryBlocks);
    Map<String, BlockView> mapFirstProductByBlock = mapFirstProductByBlock(categoryBlocks);
    Map<Integer, Block> blocksById = blocksById(categoryBlocks);
    List<CategoryProduct> sortedProduct = Lists.newArrayList();
    Map<String, CategoryProduct> productsMapByPartNumber = ProductHelper.getProductsMapByPartNumber(products);
    List<CategoryProduct> processedProducts = Lists.newArrayList();
    int j = 0;
    for (int i = 0; i < products.size(); i++) {
        CategoryProduct product = products.get(i);
        if (blocksById.isEmpty() && !processedProducts.contains(product)) {
            sortedProduct.add(j++, product);
            processedProducts.add(product);
        }
        if (!processedProducts.contains(product) && (mapFirstProductByBlock.get(product.getPartNumber()) != null
                || mapProductByBlock.get(product.getPartNumber()) == null)) {
            BlockView blockView = mapProductByBlock.get(product.getPartNumber());
            if (blockView != null) {
                Block block = blocksById.get(blockView.getBlockId());
                if (block == null) {
                    sortedProduct.add(j++, product);
                    continue;
                }
                for (BlockProduct blockProduct : block.getProducts()) {
                    CategoryProduct categoryProduct = productsMapByPartNumber.get(blockProduct.getPartnumber());
                    sortedProduct.add(j++, categoryProduct);
                    processedProducts.add(categoryProduct);
                }
                blocksById.remove(blockView.getBlockId());
            } else {
                sortedProduct.add(j++, product);
                processedProducts.add(product);
            }
        }
    }

    return sortedProduct;
}

Any advice to improve and make it faster will be welcome.欢迎任何改进和使其更快的建议。

(edit with the improved code) (使用改进的代码进行编辑)

public static List<CategoryProduct> sortProductsByBlocks2(List<CategoryProduct> products,
        CategoryBlocks categoryBlocks) {
    if (!validateCategoryBlocks(categoryBlocks)) {
        return products;
    }

    Map<String, Integer> blocksIdByFirstPartnumber = Maps.newHashMap();
    List<String> partnumbersInBlocks = Lists.newArrayList();
    for (int k = 0; k < categoryBlocks.getBlocks().size(); k++) {
        Block block = categoryBlocks.getBlocks().get(k);
        if (block != null && block.getProducts() != null) {
            for (int i = 0; i < block.getProducts().size(); i++) {
                BlockProduct blockProduct = block.getProducts().get(i);
                if (i == 0) {
                    blocksIdByFirstPartnumber.put(blockProduct.getPartnumber(), k);
                } else {
                    partnumbersInBlocks.add(blockProduct.getPartnumber());
                }
            }
        }
    }

    CategoryProduct[] result = new CategoryProduct[products.size()];
    Map<String, Integer> productsIndex = Maps.newHashMap();
    Map<String, CategoryProduct> categoryProductByPartnumber = Maps.newHashMap();
    int indexResult = 0;
    for (CategoryProduct categoryProduct : products) {
        String partNumber = categoryProduct.getPartNumber();
        if (!partnumbersInBlocks.contains(partNumber)) {
            if (blocksIdByFirstPartnumber.get(partNumber) != null) {
                Block categoryProductBlock = categoryBlocks.getBlocks()
                        .get(blocksIdByFirstPartnumber.get(partNumber));
                result[indexResult] = categoryProduct;
                indexResult++;
                for (int i = 1; i < categoryProductBlock.getProducts().size(); i++) {
                    BlockProduct blockProduct = categoryProductBlock.getProducts().get(i);
                    if (categoryProductByPartnumber.get(blockProduct.getPartnumber()) != null) {
                        result[indexResult] = categoryProductByPartnumber.get(blockProduct.getPartnumber());
                    } else {
                        productsIndex.put(blockProduct.getPartnumber(), indexResult);
                        result[indexResult] = null;
                    }
                    indexResult++;
                }
            } else {
                result[indexResult] = categoryProduct;
                indexResult++;
            }
        } else {
            if (productsIndex.get(partNumber) != null) {
                result[productsIndex.get(partNumber)] = categoryProduct;
            } else {
                categoryProductByPartnumber.put(partNumber, categoryProduct);
            }
        }
    }
    return Lists.newArrayList(Arrays.asList(result));
}

Performance:表现:

Elements New algorithm Old algorithm元素 新算法 旧算法

1200 0.002s 0.129s 1200 0.002s 0.129s

12000 0.021s 14.673s 12000 0.021s 14.673s

Form the code you submitted, I cannot figure out how your algorithm is fully working.从您提交的代码中,我无法弄清楚您的算法是如何完全工作的。

I can write another algorithm that will do the task.我可以编写另一种算法来完成这项任务。

  1. Mark the first element for each group标记每组的第一个元素

    [A,C,D] -> A
  2. Remove from list(to_be_sorted) all elements from groups that are not markedlist(to_be_sorted)删除未标记的组中的所有元素

    [A,C,D] -> remove [C,D]
  3. perform sort on list对列表执行排序

    result ([A,B,F,G,J])
  4. place removed element based on Mark根据 Mark 放置移除的元素

    Initial Sorted List [A,B,F,G,J] A->add [C,D] List is [A,C,D,B,F,G,J] B->as it is F->add [E] List is [A,C,D,B,F,E,G,J] G->as it is J->add [H,I] Final Sorted List [A,C,D,B,F,E,G,J,H,I]

Time complexity is the same as sorting algorithm时间复杂度与排序算法相同

By your definition it isn't entirely clear what the conditions are to merge the results from your given list and 'groups' ( arrays ).根据您的定义,合并给定列表和“组”(数组)中的结果的条件并不完全清楚。 However, here is a solution based on your requirements using the assertion但是,这是使用断言基于您的要求的解决方案

"You want the first element of the list not contained in any of the groups inserted between the groups... " “您希望列表的第一个元素不包含在任何插入组之间的组中......”

public class MergeArrays {

    private static final List<String> FIRST = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J"));
    private static final List<String> SECOND = new ArrayList<>(Arrays.asList("A", "C", "D"));
    private static final List<String> THIRD = new ArrayList<>(Arrays.asList("F", "E"));
    private static final List<String> FOURTH = new ArrayList<>(Arrays.asList("J", "H", "I"));

    public static List<String> merge(List<String> source, List<String>... lists) {
        List<String> result = new ArrayList<>();
        for (List<String> list : lists) {
            for (String value : list) {
                source.remove(value);
            }
        }

        for (List<String> list : lists) {
            String value = null;
            if (source.size() > 0) {
                value = source.get(0);
                source.remove(0);
            }
            result.addAll(merge(value, list));
        }
        return result;
    }

    public static List<String> merge(String value, List<String> list) {
        List<String> result = new ArrayList<>(list);
        if (value != null) {
            result.add(value);
        }
        return result;
    }

    public static void main(String[] args) {
        List<String> result = merge(FIRST, SECOND, THIRD, FOURTH);
        System.out.println(result);
    }
}

//Results //结果

[A, C, D, B, F, E, G, J, H, I]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM