How efficiently sort a list by groups?

villb :

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...

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

12000 0.021s 14.673s

Traian GEICU :

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 marked

    [A,C,D] -> remove [C,D]
    
  3. perform sort on list

    result ([A,B,F,G,J])
    
  4. place removed element based on 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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=153410&siteId=1