简体   繁体   English

打字稿映射和或减少:将数组映射到其他数组类型

[英]Typescript mapping and or reduce: Map array to other Array type

I need to map an Array<Quote> , where Quote is:我需要映射一个Array<Quote> ,其中Quote是:

export interface Quote {
    readonly chronoUnit: Quote.ChronoUnitEnum;
    readonly downloadedDocs: number;
    readonly downloadedKb: number;
    readonly uploadedKb: number;
    readonly uploadedRefs: number;
}

export namespace Quote {
    export type ChronoUnitEnum = 'HOUR' | 'DAY' | 'MONTH' | 'YEAR';
    export const ChronoUnitEnum = {
        HOUR: 'HOUR' as ChronoUnitEnum,
        DAY: 'DAY' as ChronoUnitEnum,
        MONTH: 'MONTH' as ChronoUnitEnum,
        YEAR: 'YEAR' as ChronoUnitEnum
    };
}

To an Array<AlignedQuote> :Array<AlignedQuote>

export interface AlignedQuote {
    readonly alignedType: AlignedQuote.AlignedEnum;
    readonly hour: number;
    readonly day: number;
    readonly month: number;
    readonly year: number;
}

export namespace AlignedQuote {
    export type AlignedEnum = 'DOWNLOADEDDOCS' | 'DOWNLOADEDKB' | 'UPLOADEDKB' | 'UPLOADEDREFS';
    export const AlignedEnum = {
        HOUR: 'DOWNLOADEDDOCS' as AlignedEnum,
        DAY: 'DOWNLOADEDKB' as AlignedEnum,
        MONTH: 'UPLOADEDKB' as AlignedEnum,
        YEAR: 'UPLOADEDREFS' as AlignedEnum
    };
}

I was thinking about using any kind of map , but I don't quite figure out how.我正在考虑使用任何类型的map ,但我不太清楚如何。

let quotes: Array<Quote>;
let alignedQuotes: Array<AlignedQuotes> = quotes.map(???).reduce(????);

Example:例子:

quotes: [{
  chronoUnit:ChronoUnit.HOUR,
  downloadedDocs:1,
  downloadedKb:23,
  uploadedKb:65,
  uploadedRefs:7
}];

alignedQuotes: [ 
  {alignedType: AlignedQuote.AlignedEnum.DOWNLOADEDDOCS, hour: 1, day: null, month: null, year: null},
  {alignedType: AlignedQuote.AlignedEnum.DOWNLOADEDKBS, hour: 23, day: null, month: null, year: null},
  {alignedType: AlignedQuote.AlignedEnum.UPLOADEDKBS, hour: 65, day: null, month: null, year: null},
  {alignedType: AlignedQuote.AlignedEnum.UPLOADEDREFS, hour: 7, day: null, month: null, year: null}
]

Any ideas?有任何想法吗?

I`m not sure how exactly your two objects are related, but you can check here how Array.Map() works with basic example.我不确定你的两个对象究竟是如何相关的,但你可以在这里查看 Array.Map() 如何与基本示例一起工作。 It is a function and you can do whatever you need inside the brackets这是一个函数,你可以在括号内做任何你需要的事情

Click点击

Possible solution to your case:您的情况可能的解决方案:

let alignedQuotes: Array<AlignedQuotes> = quotes.map(quote => <AlignedQuotes>{ 
     hour: quote.downloadedDocs,
     day: null, 
     month: null, 
     year: null
});

quote here is single Quote obj (.map iterates over all of them), you can use his properties when needed like in the 'hour' example.这里的quote是单引号对象(.map 遍历所有对象),您可以在需要时使用他的属性,就像在 'hour' 示例中一样。

I would break down the problem into three parts.我会将问题分解为三个部分。

  • a plucker采摘者
  • a selector选择器
  • a summer一个夏天

Based upon this example:基于这个例子:

{alignedType: AlignedQuote.AlignedEnum.DOWNLOADEDDOCS, hour: 1, day: null, month: null, year: null},

For the above, DOWNLOADEDDOCS is the plucker of which property to read, and hour is the selector of which quotes to iterate and 1 is the sum.对于上述, DOWNLOADEDDOCS是读取哪个属性的选择器, hour是要迭代的引用的选择器, 1是总和。 You need to use four different selectors to get all of hour , day , month and year for a single AlignedQuote .您需要使用四个不同的选择器来获取单个AlignedQuote所有hourdaymonthyear

So we write each of the above as separate functions.所以我们把上面的每一个都写成单独的函数。

const plucker = (quote: Quote, x: AlignedQuote.AlignedEnum): number => quote[x];
const selector = (quotes: Quote[], x: Quote.ChronoUnitEnum): Quote[] => quotes.filter(q => q.chronoUnit === x);
const sum = (nums: number[]): number => nums.reduce((acc, next) => acc + next, 0);

We want to use the above to produce a single row like this:我们想使用上面的内容来生成这样的一行:

{alignedType: AlignedQuote.AlignedEnum.DOWNLOADEDDOCS, hour: 1, day: null, month: null, year: null},

Which can be written like this:可以这样写:

const hours = {
    alignedType: AlignedQuote.AlignedEnum.HOUR,
    hour: sum(selector(quotes, ChronoUnitEnum.HOUR).map(q => pluck(q, AlignedEnum.HOUR))),
    day: null,
    month: null,
    year: null
};

Now we want to produce the above for each hour , day , month and year .现在我们要为hourdaymonthyear生成上述内容。

const nulls = {hour: null, day: null, month: null, year: null};
const totals = [
    [AlignedQuote.AlignedEnum.HOUR, ChronoUnitEnum.HOUR],
    [AlignedQuote.AlignedEnum.DAY, ChronoUnitEnum.DAY],
    [AlignedQuote.AlignedEnum.MONTH, ChronoUnitEnum.MONTH],
    [AlignedQuote.AlignedEnum.YEAR, ChronoUnitEnum.YEAR]
].map(([alignedType, unit]: [AlignedQuote.AlignedEnum, ChronoUnitEnum]) => {
    const values = {
        alignedType,
        [unit]: sum(selector(quotes, unit).map(q => pluck(q, alignedType)))
    };
    return {...nulls, ...values};
});

The above only works if the enum values match the letter case of the property fields.以上仅适用于枚举值与属性字段的字母大小写匹配的情况。 Otherwise, you'll have to add functions that convert the enum to a property field name (which is just a simple object map).否则,您必须添加将枚举转换为属性字段名称的函数(这只是一个简单的对象映射)。 But, to save time of posting an answer I just modified the enums.但是,为了节省发布答案的时间,我只是修改了枚举。

Like this:像这样:

export namespace Quote {
    export type ChronoUnitEnum = 'hour' | 'day' | 'month' | 'year';
    export const ChronoUnitEnum = {
        HOUR: 'hour' as ChronoUnitEnum,
        DAY: 'day' as ChronoUnitEnum,
        MONTH: 'month' as ChronoUnitEnum,
        YEAR: 'year' as ChronoUnitEnum
    };
}

export namespace AlignedQuote {
    export type AlignedEnum = 'downloadedDocs' | 'downloadedKb' | 'uploadedKb' | 'uploadedRefs';
    export const AlignedEnum = {
        HOUR: 'downloadedDocs' as AlignedEnum,
        DAY: 'downloadedKb' as AlignedEnum,
        MONTH: 'uploadedKb' as AlignedEnum,
        YEAR: 'uploadedRefs' as AlignedEnum
    };
}

I was able to solve your example with a reduce.我能够用reduce来解决你的例子。 You can take a look at the following code (I removed some types for the example).您可以查看以下代码(我为示例删除了一些类型)。 It's not the solution but maybe a good lead.这不是解决方案,但可能是一个很好的线索。

const quotes = [{
  chronoUnit: 'hour',
  downloadedDocs:1,
  downloadedKb:23,
  uploadedKb:65,
  uploadedRefs:7
}];

const alignedQuotes = [ 
  {alignedType: 'DOWNLOADEDDOCS', hour: 1, day: null, month: null, year: null},
  {alignedType: 'DOWNLOADEDKBS', hour: 23, day: null, month: null, year: null},
  {alignedType: 'UPLOADEDKBS', hour: 65, day: null, month: null, year: null},
  {alignedType: 'UPLOADEDREFS', hour: 7, day: null, month: null, year: null}
]

return quotes.reduce((acc, item) => {
    const quote = Object.keys(item).filter(key => key !== 'chronoUnit').map(key => {
    return {
      alignedType: key.toUpperCase(),
      hour: item['chronoUnit'] === 'hour' ? item[key] : null,
      day: item['chronoUnit'] === 'day' ? item[key] : null,
      month: item['chronoUnit'] === 'month' ? item[key] : null,
      year: item['chronoUnit'] === 'year' ? item[key] : null,
    }
  })
    return acc.concat(quote);
}, []);

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

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